Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pVPm5-0007pj-Cj for pgsql-hackers@arkaria.postgresql.org; Fri, 24 Feb 2023 04:33:37 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pVPm2-00088z-5f for pgsql-hackers@arkaria.postgresql.org; Fri, 24 Feb 2023 04:33:34 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pVPm1-00088q-P1 for pgsql-hackers@lists.postgresql.org; Fri, 24 Feb 2023 04:33:33 +0000 Received: from mail-pj1-x102d.google.com ([2607:f8b0:4864:20::102d]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1pVPlx-0003Ty-7D for pgsql-hackers@lists.postgresql.org; Fri, 24 Feb 2023 04:33:33 +0000 Received: by mail-pj1-x102d.google.com with SMTP id z20-20020a17090a8b9400b002372d7f823eso1538434pjn.4 for ; Thu, 23 Feb 2023 20:33:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=NAhJT+eBGh3S8dNGzvSjS21R8t2z/BAXA+2qYQ2v8u4=; b=eqHBVvH3QelMiWS7B8R/PtQn7A0mlCDbb2t1HhB7fb9ITSnKqqI7mr7c1I3GbbWIhb eN43YqjMxS6flEcrI44xl+r8Kz7/j/24iEugmBFkCp2DTy6A8UF+bVlLtFXia10jEM8T 4bX6jn5oOYohtHrdtIteGGV3AT/brFVkNczPTC5gS9lw/bvdK3iwScPHrw+tYzdcCxY0 AAjpnONqOQH5eJZztWpWkLkgt9bCTpUf5LrmKjKpvPTFKDgDq2HgyZ31BFg/9AbjB9OV CLxHu2dqr6EqJlMzgjwUWpjtCIYxAOZ/76GUUJX465OlFfM5wQ/Uidud5eSmKcOtzwZB Qc5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=NAhJT+eBGh3S8dNGzvSjS21R8t2z/BAXA+2qYQ2v8u4=; b=6ltxL6CJS9AujXCO89q6j3pN0Ox7iHOvYiRE0dy51r4QAo7HdrAZuwCHsV57TczHwa qYBZPFWYaYK5ONXBfeJ1TPLqkJ1PW7OBgVg5WlhwCqEy3HlFOZ6y+yv6w7D39XUcyQ1y cei0lb253HjiVQ5Lvg1hnduIPpU+LuN5nrvLBCTuw6ZWpA9k58klIDUdoP0pxUNbjGD3 mvzjYpd/gnc+EYMVPfEk7xYpFo5cO67jv9B1Jg4qGsuaaOXdCJzPUW5fWueCxCnF40xS JEnCS1aSers0uHkYRb8lMsXGSg/DLwazFy4/6UtAFm68lmM9kz62tE3TCJvUyb9KemS4 j32g== X-Gm-Message-State: AO0yUKVDT9/UK0VbggSACC2XpjgtmQjo4me7QSJYqSrKU/+rZN9XwgBu Vp5JCK+FFtGyub1JUy3jT/g= X-Google-Smtp-Source: AK7set/p5wp2yjIR6J7Na/RVXf3WPlsYUoN62/78z7u+iTKzCb4/uzjWYzoMBK3/+ixSmlnvSjN6UQ== X-Received: by 2002:a05:6a20:258c:b0:cc:851b:16cb with SMTP id k12-20020a056a20258c00b000cc851b16cbmr50720pzd.47.1677213206513; Thu, 23 Feb 2023 20:33:26 -0800 (PST) Received: from nathanxps13 ([50.47.162.83]) by smtp.gmail.com with ESMTPSA id r16-20020a62e410000000b005a91d570972sm5596433pfh.41.2023.02.23.20.33.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Feb 2023 20:33:25 -0800 (PST) Date: Thu, 23 Feb 2023 20:33:23 -0800 From: Nathan Bossart To: Thomas Munro Cc: Michael Paquier , Andres Freund , Robert Haas , Tom Lane , Fujii Masao , Postgres hackers Subject: Re: stopgap fix for signal handling during restore_command Message-ID: <20230224043323.GA821522@nathanxps13> References: <20230223231503.GA743455@nathanxps13> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="u3/rZRmxL6MmkK24" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --u3/rZRmxL6MmkK24 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Feb 24, 2023 at 01:25:01PM +1300, Thomas Munro wrote: > I think you should have a trailing \n when writing to stderr. Oops. I added that in v7. > Here's that reproducer I speculated about (sorry I confused SIGQUIT > and SIGTERM in my earlier email, ENOCOFFEE). Seems to do the job, and > I tested on a Linux box for good measure. If you comment out the > kill(), "check PROVE_TESTS=t/002_archiving.pl" works fine > (demonstrating that that definition of system() works fine). With the > kill(), it reliably reaches 'TRAP: failed Assert("latch->owner_pid == > MyProcPid")' without your patch, and with your patch it avoids it. (I > believe glibc's system() could reach it too with the right timing, but > I didn't try, my point being that the use of the OpenBSD system() here > is only because it's easier to grok and to wrangle.) Thanks for providing the reproducer! I am seeing the behavior that you described on my Linux machine. -- Nathan Bossart Amazon Web Services: https://aws.amazon.com --u3/rZRmxL6MmkK24 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v7-0001-Move-extra-code-out-of-the-Pre-PostRestoreCommand.patch" From 6bdafd9980854fc9d81f37d450b86e5f5d4a9d84 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Thu, 23 Feb 2023 14:27:48 -0800 Subject: [PATCH v7 1/2] Move extra code out of the Pre/PostRestoreCommand() block. If SIGTERM is received within this block, the startup process will immediately proc_exit() in the signal handler, so it is inadvisable to include any more code than is required in this section. This change moves the code recently added to this block (see 1b06d7b and 7fed801) to outside of the block. This ensures that only system() is called while proc_exit() might be called in the SIGTERM handler, which is how this code worked from v8.4 to v14. --- src/backend/access/transam/xlogarchive.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index fcc87ff44f..41684418b6 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -159,20 +159,27 @@ RestoreArchivedFile(char *path, const char *xlogfname, (errmsg_internal("executing restore command \"%s\"", xlogRestoreCmd))); + fflush(NULL); + pgstat_report_wait_start(WAIT_EVENT_RESTORE_COMMAND); + /* - * Check signals before restore command and reset afterwards. + * PreRestoreCommand() informs the SIGTERM handler for the startup process + * that it should proc_exit() right away. This is done for the duration of + * the system() call because there isn't a good way to break out while it + * is executing. Since we might call proc_exit() in a signal handler, it + * is best to put any additional logic before or after the + * PreRestoreCommand()/PostRestoreCommand() section. */ PreRestoreCommand(); /* * Copy xlog from archival storage to XLOGDIR */ - fflush(NULL); - pgstat_report_wait_start(WAIT_EVENT_RESTORE_COMMAND); rc = system(xlogRestoreCmd); - pgstat_report_wait_end(); PostRestoreCommand(); + + pgstat_report_wait_end(); pfree(xlogRestoreCmd); if (rc == 0) -- 2.25.1 --u3/rZRmxL6MmkK24 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v7-0002-Don-t-proc_exit-in-startup-s-SIGTERM-handler-if-f.patch" From 52b0ad1a8b8a94db1f540b7cbf916bc9b1a785b6 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Tue, 14 Feb 2023 09:44:53 -0800 Subject: [PATCH v7 2/2] Don't proc_exit() in startup's SIGTERM handler if forked by system(). Instead, emit a message to STDERR and _exit() in this case. This change also adds assertions to proc_exit(), ProcKill(), and AuxiliaryProcKill() to verify that these functions are not called by a process forked by system(), etc. --- src/backend/postmaster/startup.c | 20 +++++++++++++++++++- src/backend/storage/ipc/ipc.c | 3 +++ src/backend/storage/lmgr/proc.c | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index efc2580536..bace915881 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -19,6 +19,8 @@ */ #include "postgres.h" +#include + #include "access/xlog.h" #include "access/xlogrecovery.h" #include "access/xlogutils.h" @@ -121,7 +123,23 @@ StartupProcShutdownHandler(SIGNAL_ARGS) int save_errno = errno; if (in_restore_command) - proc_exit(1); + { + /* + * If we are in a child process (e.g., forked by system() in + * RestoreArchivedFile()), we don't want to call any exit callbacks. + * The parent will take care of that. + */ + if (MyProcPid == (int) getpid()) + proc_exit(1); + else + { + const char msg[] = "StartupProcShutdownHandler() called in child process\n"; + int rc pg_attribute_unused(); + + rc = write(STDERR_FILENO, msg, sizeof(msg)); + _exit(1); + } + } else shutdown_requested = true; WakeupRecovery(); diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index 1904d21795..d5097dc008 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -103,6 +103,9 @@ static int on_proc_exit_index, void proc_exit(int code) { + /* proc_exit() is not safe in forked processes from system(), etc. */ + Assert(MyProcPid == (int) getpid()); + /* Clean up everything that must be cleaned up */ proc_exit_prepare(code); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 22b4278610..e3da0622d7 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -805,6 +805,7 @@ ProcKill(int code, Datum arg) dlist_head *procgloballist; Assert(MyProc != NULL); + Assert(MyProcPid == (int) getpid()); /* not safe if forked by system(), etc. */ /* Make sure we're out of the sync rep lists */ SyncRepCleanupAtProcExit(); @@ -925,6 +926,7 @@ AuxiliaryProcKill(int code, Datum arg) PGPROC *proc; Assert(proctype >= 0 && proctype < NUM_AUXILIARY_PROCS); + Assert(MyProcPid == (int) getpid()); /* not safe if forked by system(), etc. */ auxproc = &AuxiliaryProcs[proctype]; -- 2.25.1 --u3/rZRmxL6MmkK24--