From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 7BDD01FF0AE for ; Tue, 15 Sep 2026 15:36:45 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 93D36215C4; Tue, 15 Sep 2026 15:36:42 +0200 (CEST) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH pve-manager] pvescheduler: hold off HUP and CHLD while a child is forked and recorded Date: Tue, 15 Sep 2026 15:36:36 +0200 Message-ID: <20260915133636.858359-1-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1789479384319 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.515 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: NODESKJKQAJN2KVTEQLUR32KOFOQJGHB X-Message-ID-Hash: NODESKJKQAJN2KVTEQLUR32KOFOQJGHB X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: A HUP that lands between the fork and recording neither stops nor hands over that child, since the hand-over string is built in the HUP handler from what is recorded. A CHLD from a child that exits right after the fork, before it is recorded, is missed by the reap it triggers and cleared only at the next CHLD from an unrelated child. Hold both signals off until the child is recorded, and once a HUP came in fork nothing more, since the hand-over is already put together. Signed-off-by: Hannes Laimer --- really really tight timeframe, but these workers can be really fast if nothing has to be done, either way, we should address this, even if unlikely PVE/Service/pvescheduler.pm | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/PVE/Service/pvescheduler.pm b/PVE/Service/pvescheduler.pm index f7271fc0..be33db6e 100755 --- a/PVE/Service/pvescheduler.pm +++ b/PVE/Service/pvescheduler.pm @@ -3,7 +3,7 @@ package PVE::Service::pvescheduler; use strict; use warnings; -use POSIX qw(WNOHANG); +use POSIX qw(WNOHANG SIGCHLD SIGHUP SIG_BLOCK SIG_SETMASK); use PVE::Jobs; use PVE::SafeSyslog; @@ -80,10 +80,20 @@ sub run { # FIXME: some job types may handle this better themself or just not care - make configurable return if scalar(keys $self->{jobs}->{$type}->%*); + # recorded before a HUP hands children over or a CHLD reaps them + my $prev_mask = POSIX::SigSet->new(); + POSIX::sigprocmask(SIG_BLOCK, POSIX::SigSet->new(SIGHUP, SIGCHLD), $prev_mask); + # the hand-over is already built once a HUP came in + if ($self->{got_hup_signal}) { + POSIX::sigprocmask(SIG_SETMASK, $prev_mask); + return; + } my $child = fork(); if (!defined($child)) { + POSIX::sigprocmask(SIG_SETMASK, $prev_mask); die "fork failed: $!\n"; } elsif ($child == 0) { + POSIX::sigprocmask(SIG_SETMASK, $prev_mask); $self->after_fork_cleanup(); eval { $sub->(); }; if (my $err = $@) { @@ -93,6 +103,7 @@ sub run { } $jobs->{$type}->{$child} = 1; + POSIX::sigprocmask(SIG_SETMASK, $prev_mask); }; my $first_run = 1; -- 2.47.3