Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vmv20-000At1-1L for pgsql-hackers@arkaria.postgresql.org; Mon, 02 Feb 2026 14:36:00 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vmv0y-00EEOz-2f for pgsql-hackers@arkaria.postgresql.org; Mon, 02 Feb 2026 14:34:57 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vmv0y-00EEOq-1P for pgsql-hackers@lists.postgresql.org; Mon, 02 Feb 2026 14:34:57 +0000 Received: from fout-a4-smtp.messagingengine.com ([103.168.172.147]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1vmv0w-00000000gc1-2Jae for pgsql-hackers@postgresql.org; Mon, 02 Feb 2026 14:34:56 +0000 Received: from phl-compute-03.internal (phl-compute-03.internal [10.202.2.43]) by mailfout.phl.internal (Postfix) with ESMTP id 19172EC0386; Mon, 2 Feb 2026 09:34:53 -0500 (EST) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Mon, 02 Feb 2026 09:34:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kurilemu.de; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :reply-to:subject:subject:to:to; s=fm1; t=1770042893; x= 1770129293; bh=Wg9GyQMWP7kvkxfzHRaYoPxtQGzcCJHsUztDP9aWIic=; b=h t+4MqUM60Rb8yiPHMiASCuzg2ntW7J0YDVzbVcPPVB7ltn4Up5+HcRJooP700oxY oTw5i8Pdkkpr906uIIi/eFy8z6+hc4lPWDJMcYS/5i6HL3448p+p3dQHVoAC5MFq Oy3P3kI0bK5naZvcqxMfCv18QtX1yoPQ0/D+HzNcJIpb9r+Wk6qpH/Yz2k/3w5o3 qupbjSvKBxJTeniX1QWDWvhttN78ovhkEYqWq58gRnTEgFzvOB1LiLhrYz7I+ZAw xi3ElRbGJsyWOA0TYIJ7V8df26c01OK8VOGhQiDJ/+Yl2LrVrysbXDi4mrfDYTbJ fOmZJQijIBbfYNPqgqR5g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1770042893; x=1770129293; bh=W g9GyQMWP7kvkxfzHRaYoPxtQGzcCJHsUztDP9aWIic=; b=Eqpi9V6J96PikGFnn PO2PLpXmFj1Pf1rEkkl2MdhHyBsIi+QCCWi4f9SJJcPCD/d+yc1yOMvS9+L0Ro9B s6Hlj2vP4cst4Gx4Wkdsz+5/REiqUYENYAPFeKEu1Q1jRgQMWYNRlBjD9uTg3qiv 4UzrPf108ABGnjObpAOsBq1DXwo3O33diXIoUgEYrh/tMcTktT30fyNjmX9rHP4G GAOzfqfeTbk7DhN7x9WGOsVGREa+jnR4ZhjNvcCcGxQ4T1i+YGNKeFpd90VP+qiO UJ3WAc7uu6Grxi/X3ekApmKq+VeY5P229AIZu9JAPYtcbQK6+ViWEks/Bgut/8// qpEUQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddujeejkeelucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepfffhvfevuffkgggtugfgjgesmhekreertddtjeenucfhrhhomheplmhlvhgrrhho ucfjvghrrhgvrhgruceorghlvhhhvghrrhgvsehkuhhrihhlvghmuhdruggvqeenucggtf frrghtthgvrhhnpeeugfekkedtjeduhfeufefhjeevhffffedvvddvfeejjefhueektdeg fedtveegjeenucffohhmrghinhepphhoshhtghhrvghsqhhlrdhorhhgpdgvnhhtvghrph hrihhsvggusgdrtghomhenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgr ihhlfhhrohhmpegrlhhvhhgvrhhrvgeskhhurhhilhgvmhhurdguvgdpnhgspghrtghpth htohepkedpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtoheprghnughrvghssegrnhgr rhgriigvlhdruggvpdhrtghpthhtohepmhgvlhgrnhhivghplhgrghgvmhgrnhesghhmrg hilhdrtghomhdprhgtphhtthhopehnrghthhgrnhgusghoshhsrghrthesghhmrghilhdr tghomhdprhgtphhtthhopehthhhomhgrshdrmhhunhhrohesghhmrghilhdrtghomhdprh gtphhtthhopehmrghsrghordhfuhhjihhisehoshhsrdhnthhtuggrthgrrdgtohhmpdhr tghpthhtohepmhhitghhrggvlhesphgrqhhuihgvrhdrgiihiidprhgtphhtthhopehpgh hsqhhlqdhhrggtkhgvrhhssehpohhsthhgrhgvshhqlhdrohhrghdprhgtphhtthhopeht ghhlsehsshhsrdhpghhhrdhprgdruhhs X-ME-Proxy: Feedback-ID: ie3de48e3:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 2 Feb 2026 09:34:51 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kurilemu.de; s=schmee; t=1770042887; bh=HdM63VSzRA8RppF/Uz5rDkBvHkaTA4v1LBt55oV15aE=; h=Date:From:To:Cc:Subject:In-Reply-To:From; b=v7J54pKWExo+HZr0BKv9y2MFjHZuyljTrafGANF/lJ5CoYjWIsC53nmUjm2jk0HP/ fShGFaf6nDA6FmnCnbYDHxr5hYqiz9V6X3ikTuGMxoOdR8Ch28wZcl0NbyY/jaKsKj oTVhOWI07qXi8IZxIw0m/gytQNo28tOTrU4hWPoDCl92OaEPDffWBKU2ZUhLTmiqP3 iIDuD5+K81clBQ9VIgZm/mo2Wu1+GUEony5uDbheOSuaAHI7hiLJyJ3n/WgC7FH+f8 zhi/DfaFSzaxdG3IE5RyaKvk95IpI98hZHdhhc+6Q3HkSH7Q8lzfGFLL93znsJDnXD RFb1IsFDaGozg== Received: by schmee.kurilemu.internal (Postfix, from userid 1000) id 2E34A74; Mon, 02 Feb 2026 15:34:47 +0100 (CET) Date: Mon, 2 Feb 2026 15:34:47 +0100 From: =?utf-8?Q?=C3=81lvaro?= Herrera To: Thomas Munro Cc: Andres Freund , Tom Lane , Nathan Bossart , Melanie Plageman , Michael Paquier , Fujii Masao , "pgsql-hackers@postgresql.org" Subject: Re: race condition when writing pg_control Message-ID: <202602021426.ztjk2wp6sgiy@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="dhbc6bswyy6qufwn" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --dhbc6bswyy6qufwn Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2024-May-18, Thomas Munro wrote: > First idea idea I've come up with to avoid all of that: pass a copy of > the "proto-controlfile", to coin a term for the one read early in > postmaster startup by LocalProcessControlFile(). As far as I know, > the only reason we need it is to suck some settings out of it that > don't change while a cluster is running (mostly can't change after > initdb, and checksums can only be {en,dis}abled while down). Right? > Children can just "import" that sucker instead of calling > LocalProcessControlFile() to figure out the size of WAL segments yada > yada, I think? Later they will attach to the real one in shared > memory for all future purposes, once normal interlocking is allowed. > > I dunno. Draft patch attached. Better plans welcome. This passes CI > on Linux systems afflicted by EXEC_BACKEND, and Windows. Thoughts? Has this problem been addressed? Looking at the known-buildfarm- failures page, https://wiki.postgresql.org/wiki/Known_Buildfarm_Test_Failures#culicidae_failed_to_restart_server_due_to_incorrect_checksum_in_control_file there are still some failures of that ilk, last in 2026-01-21. So, was this "proto-controlfile" idea discarded? I see Noah downthread proposed something somewhat more sophisticated than this, setting some values to garbage to prevent reading invalid values. I imagine that would be on top of Thomas' patch, so I have rebased it and moved to the next commitfest. Thanks -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/ "Crear es tan difícil como ser libre" (Elsa Triolet) --dhbc6bswyy6qufwn Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="v2-0001-Fix-pg_control-corruption-in-EXEC_BACKEND-startup.patch" From 1c998da8805cb172a4d5e3fe322a6984e1ba1e39 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Sat, 18 May 2024 13:41:09 +1200 Subject: [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn--