From: "Daniel P. Berrangé" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Daniel P. Berrangé" <berrange@redhat.com>,
"Fabiano Rosas" <farosas@suse.de>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Marc-André Lureau" <marcandre.lureau@redhat.com>,
devel@lists.libvirt.org, "Laurent Vivier" <lvivier@redhat.com>,
"Richard W.M. Jones" <rjones@redhat.com>
Subject: [PULL 01/32] Implement -run-with exit-with-parent=on
Date: Mon, 3 Nov 2025 13:36:55 +0000 [thread overview]
Message-ID: <20251103133727.423041-2-berrange@redhat.com> (raw)
In-Reply-To: <20251103133727.423041-1-berrange@redhat.com>
From: Richard W.M. Jones <rjones@redhat.com>
Libguestfs wants to use qemu to run a captive appliance. When the
program linked to libguestfs exits, we want qemu to be cleaned up.
Libguestfs goes to great lengths to do this at the moment: it either
forks a separate process to ensure clean-up is done, or it asks
libvirt to clean up the qemu process. However this is complicated and
not totally reliable.
On Linux, FreeBSD and macOS, there are mechanisms to ensure a signal
or message is delivered to a process when its parent process goes
away. The qemu test suite even uses this mechanism on Linux (see
PR_SET_PDEATHSIG in tests/qtest/libqtest.c).
In nbdkit we have long had the concept of running nbdkit captively,
and we have the nbdkit --exit-with-parent flag to help
(https://libguestfs.org/nbdkit-captive.1.html#EXIT-WITH-PARENT)
This commit adds the same mechanism. The syntax is:
qemu -run-with exit-with-parent=on [...]
This is not a feature that most typical users of qemu (for running
general purpose, long-lived VMs) should use, so it defaults to off.
The exit-with-parent.[ch] files are copied from nbdkit, where they
have a 3-clause BSD license which is compatible with qemu:
https://gitlab.com/nbdkit/nbdkit/-/tree/master/common/utils?ref_type=heads
Thanks: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
include/qemu/exit-with-parent.h | 57 +++++++++++++
qemu-options.hx | 13 ++-
system/exit-with-parent.c | 140 ++++++++++++++++++++++++++++++++
system/meson.build | 1 +
system/vl.c | 13 +++
5 files changed, 222 insertions(+), 2 deletions(-)
create mode 100644 include/qemu/exit-with-parent.h
create mode 100644 system/exit-with-parent.c
diff --git a/include/qemu/exit-with-parent.h b/include/qemu/exit-with-parent.h
new file mode 100644
index 0000000000..c00b863fe9
--- /dev/null
+++ b/include/qemu/exit-with-parent.h
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Originally derived from nbdkit common/utils/exit-with-parent.h
+ * Copyright Red Hat
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef NBDKIT_EXIT_WITH_PARENT_H
+#define NBDKIT_EXIT_WITH_PARENT_H
+
+/* Test if the feature is available on the platform. */
+static inline bool can_exit_with_parent(void)
+{
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+/*
+ * --exit-with-parent: kill the current process if the parent exits.
+ * This may return -1 on error.
+ *
+ * Note this will abort on platforms where can_exit_with_parent()
+ * returned false.
+ */
+extern int set_exit_with_parent(void);
+
+#endif /* NBDKIT_EXIT_WITH_PARENT_H */
diff --git a/qemu-options.hx b/qemu-options.hx
index 0223ceffeb..fca2b7bc74 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -5467,15 +5467,18 @@ DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL)
#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN)
DEF("run-with", HAS_ARG, QEMU_OPTION_run_with,
- "-run-with [async-teardown=on|off][,chroot=dir][user=username|uid:gid]\n"
+ "-run-with [async-teardown=on|off][,chroot=dir]\n" \
+ " [,exit-with-parent=on|off][,user=username|uid:gid]\n"
" Set miscellaneous QEMU process lifecycle options:\n"
" async-teardown=on enables asynchronous teardown (Linux only)\n"
+ " exit-with-parent=on causes QEMU to exit if the parent\n"
+ " process of QEMU exits (Linux, FreeBSD, macOS only)\n"
" chroot=dir chroot to dir just before starting the VM\n"
" user=username switch to the specified user before starting the VM\n"
" user=uid:gid ditto, but use specified user-ID and group-ID instead\n",
QEMU_ARCH_ALL)
SRST
-``-run-with [async-teardown=on|off][,chroot=dir][user=username|uid:gid]``
+``-run-with [async-teardown=on|off][,chroot=dir][,exit-with-parent=on|off][,user=username|uid:gid]``
Set QEMU process lifecycle options.
``async-teardown=on`` enables asynchronous teardown. A new process called
@@ -5493,6 +5496,12 @@ SRST
immediately before starting the guest execution. This is especially useful
in combination with ``user=...``.
+ ``exit-with-parent=on`` causes QEMU to exit if the parent process of
+ QEMU exits. This can be used when QEMU runs a captive appliance,
+ where the lifetime of the appliance is scoped to the parent process.
+ In case the parent process crashes, QEMU is still cleaned up.
+ This only works on Linux, FreeBSD and macOS platforms.
+
``user=username`` or ``user=uid:gid`` can be used to drop root privileges
before starting guest execution. QEMU will use the ``setuid`` and ``setgid``
system calls to switch to the specified identity. Note that the
diff --git a/system/exit-with-parent.c b/system/exit-with-parent.c
new file mode 100644
index 0000000000..df65d2231a
--- /dev/null
+++ b/system/exit-with-parent.c
@@ -0,0 +1,140 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Originally derived from nbdkit common/utils/exit-with-parent.c
+ * Copyright Red Hat
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Implement the --exit-with-parent feature on operating systems which
+ * support it.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/exit-with-parent.h"
+
+#if defined(__linux__)
+
+#include <sys/prctl.h>
+
+/*
+ * Send SIGTERM to self when the parent exits. This will cause
+ * qemu_system_killed() to be called.
+ *
+ * PR_SET_PDEATHSIG has been defined since Linux 2.1.57.
+ */
+int
+set_exit_with_parent(void)
+{
+ return prctl(PR_SET_PDEATHSIG, SIGTERM);
+}
+
+#elif defined(__FreeBSD__)
+
+#include <sys/procctl.h>
+
+/*
+ * Send SIGTERM to self when the parent exits. This will cause
+ * qemu_system_killed() to be called.
+ *
+ * PROC_PDEATHSIG_CTL has been defined since FreeBSD 11.2.
+ */
+int
+set_exit_with_parent(void)
+{
+ const int sig = SIGTERM;
+ return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, (void *) &sig);
+}
+
+#elif defined(__APPLE__)
+
+/* For macOS. */
+
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+#include "system/runstate.h"
+#include <sys/event.h>
+
+static void *
+exit_with_parent_loop(void *vp)
+{
+ const pid_t ppid = getppid();
+ int fd;
+ struct kevent kev, res[1];
+ int r;
+
+ /* Register the kevent to wait for ppid to exit. */
+ fd = kqueue();
+ if (fd == -1) {
+ error_report("exit_with_parent_loop: kqueue: %m");
+ return NULL;
+ }
+ EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL);
+ if (kevent(fd, &kev, 1, NULL, 0, NULL) == -1) {
+ error_report("exit_with_parent_loop: kevent: %m");
+ close(fd);
+ return NULL;
+ }
+
+ /* Wait for the kevent to happen. */
+ r = kevent(fd, 0, 0, res, 1, NULL);
+ if (r == 1 && res[0].ident == ppid) {
+ /* Behave like Linux and FreeBSD above, as if SIGTERM was sent */
+ qemu_system_killed(SIGTERM, ppid);
+ }
+
+ return NULL;
+}
+
+int
+set_exit_with_parent(void)
+{
+ QemuThread exit_with_parent_thread;
+
+ /*
+ * We have to block waiting for kevent, so that requires that we
+ * start a background thread.
+ */
+ qemu_thread_create(&exit_with_parent_thread,
+ "exit-parent",
+ exit_with_parent_loop, NULL,
+ QEMU_THREAD_DETACHED);
+ return 0;
+}
+
+#else /* any platform that doesn't support this function */
+
+int
+set_exit_with_parent(void)
+{
+ g_assert_not_reached();
+}
+
+#endif
diff --git a/system/meson.build b/system/meson.build
index 6d21ff9faa..4b69ef0f5f 100644
--- a/system/meson.build
+++ b/system/meson.build
@@ -15,6 +15,7 @@ system_ss.add(files(
'datadir.c',
'dirtylimit.c',
'dma-helpers.c',
+ 'exit-with-parent.c',
'globals.c',
'ioport.c',
'ram-block-attributes.c',
diff --git a/system/vl.c b/system/vl.c
index 29f5389151..5091fe52d9 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -53,6 +53,7 @@
#include "qemu/sockets.h"
#include "qemu/accel.h"
#include "qemu/async-teardown.h"
+#include "qemu/exit-with-parent.h"
#include "hw/usb.h"
#include "hw/isa/isa.h"
#include "hw/scsi/scsi.h"
@@ -783,6 +784,10 @@ static QemuOptsList qemu_run_with_opts = {
.name = "chroot",
.type = QEMU_OPT_STRING,
},
+ {
+ .name = "exit-with-parent",
+ .type = QEMU_OPT_BOOL,
+ },
{
.name = "user",
.type = QEMU_OPT_STRING,
@@ -3691,6 +3696,14 @@ void qemu_init(int argc, char **argv)
if (str) {
os_set_chroot(str);
}
+ if (qemu_opt_get_bool(opts, "exit-with-parent", false)) {
+ if (!can_exit_with_parent()) {
+ error_report("exit-with-parent is not available"
+ " on this platform");
+ exit(1);
+ }
+ set_exit_with_parent();
+ }
str = qemu_opt_get(opts, "user");
if (str) {
if (!os_set_runas(str)) {
--
2.51.1
next prev parent reply other threads:[~2025-11-03 13:40 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-03 13:36 [PULL 00/32] Next pr patches Daniel P. Berrangé
2025-11-03 13:36 ` Daniel P. Berrangé [this message]
2025-11-03 13:36 ` [PULL 02/32] tests/qtest: Use exit-with-parent=on in qtest invocations Daniel P. Berrangé
2025-11-03 13:36 ` [PULL 03/32] crypto/hash: Have hashing functions take void * buffer argument Daniel P. Berrangé
2025-11-03 13:36 ` [PULL 04/32] io/channel: Have read/write " Daniel P. Berrangé
2025-11-03 13:36 ` [PULL 05/32] io: add a "blocking" field to QIOChannelSocket Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 06/32] io: flush zerocopy socket error queue on sendmsg failure due to ENOBUF Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 07/32] crypto: bump min gnutls to 3.7.5 Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 08/32] crypto: unconditionally enable gnutls XTS support Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 09/32] crypto: bump min libgcrypt to 1.9.4 Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 10/32] crypto: bump min nettle to 3.7.3 Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 11/32] crypto: drop in-tree XTS cipher mode impl Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 12/32] crypto: remove redundant parameter checking CA certs Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 13/32] crypto: add missing free of certs array Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 14/32] crypto: replace stat() with access() for credential checks Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 15/32] crypto: remove redundant access() checks before loading certs Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 16/32] crypto: move check for TLS creds 'dir' property Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 17/32] crypto: use g_autofree when loading x509 credentials Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 18/32] crypto: remove needless indirection via parent_obj field Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 19/32] crypto: move release of DH parameters into TLS creds parent Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 20/32] crypto: shorten the endpoint == server check in TLS creds Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 21/32] crypto: remove duplication loading x509 CA cert Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 22/32] crypto: reduce duplication in handling TLS priority strings Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 23/32] crypto: introduce method for reloading TLS creds Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 24/32] crypto: introduce a wrapper around gnutls credentials Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 25/32] crypto: fix lifecycle handling of gnutls credentials objects Daniel P. Berrangé
2026-04-03 18:25 ` Maciej S. Szmigiero
2026-04-17 13:31 ` Maciej S. Szmigiero
2026-04-23 13:45 ` Daniel P. Berrange
2026-04-23 19:07 ` Maciej S. Szmigiero
2025-11-03 13:37 ` [PULL 26/32] crypto: make TLS credentials structs private Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 27/32] crypto: deprecate use of external dh-params.pem file Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 28/32] crypto: avoid loading the CA certs twice Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 29/32] crypto: avoid loading the identity " Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 30/32] crypto: expand logic to cope with multiple certificate identities Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 31/32] crypto: support upto 5 parallel " Daniel P. Berrangé
2025-11-03 13:37 ` [PULL 32/32] docs: creation of x509 certs compliant with post-quantum crypto Daniel P. Berrangé
2025-11-04 15:19 ` [PULL 00/32] Next pr patches Richard Henderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251103133727.423041-2-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=devel@lists.libvirt.org \
--cc=farosas@suse.de \
--cc=lvivier@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=rjones@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.