From nobody Wed Feb 11 06:14:33 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1676394592; cv=none; d=zohomail.com; s=zohoarc; b=h1QMJBc9hTRwS5Mp8Gr1pKockjXUr/fsPwsNOqeMOIUjihwG2vTJK5lpiP2GN8Ua8I9u6hLOtD61FdvHjGJVqIcoRpmBR7WkBGnSnGfHCDTqt3ej7zsYGURn1WwcBFrAI2sI1MqVpo19xHpA1A6k8KfghqXEGS/oVecXzelI1NA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1676394592; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=1us2wAmyoZiMp+moXxX+iqGTB3f12XhxVRu+E9nFfcs=; b=Uis3Fc1KZfEXNMYhiCd5zPzqhB/YFdZGToCYpmUJ4D7sdAXqd/wLEW22/Of8A9fJc+rZwjGoSlKEtC2Wf3GU6AY6WoaZMOoksLllsyDk9Vz054sDg4mRaY3OJY1QEOsjzfYo00K+z/cMyXscxb24GrtKhsF3flXNTk8ZfhCzCHI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1676394592509788.9947741326844; Tue, 14 Feb 2023 09:09:52 -0800 (PST) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-498-9Y6_2lNSOhek0yUq4JUrBw-1; Tue, 14 Feb 2023 12:09:47 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E8A9C2817235; Tue, 14 Feb 2023 17:09:42 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id D4322112131E; Tue, 14 Feb 2023 17:09:42 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id EFDBF19543A6; Tue, 14 Feb 2023 17:08:44 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id D1EE21946A46 for ; Tue, 14 Feb 2023 17:08:31 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id BA83F18EC7; Tue, 14 Feb 2023 17:08:26 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.8.15]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9802F18EC2 for ; Tue, 14 Feb 2023 17:08:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1676394591; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=1us2wAmyoZiMp+moXxX+iqGTB3f12XhxVRu+E9nFfcs=; b=CT0BZTX44EmhekbbV52/Klcr7osVb4n5K0FZAfvqZd1fxTIKpdYyFsIPmoG4cvGta5JJdK JkQzeNtjRggfMPbdYfi5DRELVHDys1mduO6aH6R2QvJDIV7oE8Jh2Q/RsaAkWyN03C64/i GyyOxLe+XDTpqvh3F5Tl2gx7oAuTR6w= X-MC-Unique: 9Y6_2lNSOhek0yUq4JUrBw-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH v5 25/32] qemu: Monitor nbdkit process for exit Date: Tue, 14 Feb 2023 11:08:12 -0600 Message-Id: <20230214170819.3143132-26-jjongsma@redhat.com> In-Reply-To: <20230214170819.3143132-1-jjongsma@redhat.com> References: <20230214170819.3143132-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1676394592766100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Adds the ability to monitor the nbdkit process so that we can take action in case the child exits unexpectedly. When the nbdkit process exits, we pause the vm, restart nbdkit, and then resume the vm. This allows the vm to continue working in the event of a nbdkit failure. Eventually we may want to generalize this functionality since we may need something similar for e.g. qemu-storage-daemon, etc. The process is monitored with the pidfd_open() syscall if it exists (since linux 5.3). Otherwise it resorts to checking whether the process is alive once a second. The one-second time period was chosen somewhat arbitrarily. Signed-off-by: Jonathon Jongsma Reviewed-by: Peter Krempa --- meson.build | 7 ++ src/qemu/qemu_nbdkit.c | 147 ++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_nbdkit.h | 4 +- src/qemu/qemu_process.c | 4 +- 4 files changed, 155 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index e498b49be4..048b15ff71 100644 --- a/meson.build +++ b/meson.build @@ -645,6 +645,13 @@ symbols =3D [ [ 'sched.h', 'cpu_set_t' ], ] =20 +if host_machine.system() =3D=3D 'linux' + symbols +=3D [ + # process management + [ 'sys/syscall.h', 'SYS_pidfd_open' ], + ] +endif + foreach symbol : symbols if cc.has_header_symbol(symbol[0], symbol[1], args: '-D_GNU_SOURCE', pre= fix: symbol.get(2, '')) conf.set('WITH_DECL_@0@'.format(symbol[1].to_upper()), 1) diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c index e6d3232a1e..74e2ceee19 100644 --- a/src/qemu/qemu_nbdkit.c +++ b/src/qemu/qemu_nbdkit.c @@ -19,9 +19,11 @@ =20 #include #include +#include =20 #include "vircommand.h" #include "virerror.h" +#include "virevent.h" #include "virlog.h" #include "virpidfile.h" #include "virsecureerase.h" @@ -35,6 +37,7 @@ #include "qemu_nbdkit.h" #define LIBVIRT_QEMU_NBDKITPRIV_H_ALLOW #include "qemu_nbdkitpriv.h" +#include "qemu_process.h" #include "qemu_security.h" =20 #include @@ -613,6 +616,123 @@ qemuNbdkitCapsCacheNew(const char *cachedir) } =20 =20 +static void +qemuNbdkitProcessRestart(qemuNbdkitProcess *proc, + virDomainObj *vm) +{ + qemuDomainObjPrivate *vmpriv =3D vm->privateData; + virQEMUDriver *driver =3D vmpriv->driver; + + /* clean up resources associated with process */ + qemuNbdkitProcessStop(proc); + + if (qemuNbdkitProcessStart(proc, vm, driver) < 0) + VIR_WARN("Unable to restart nbkdit process"); +} + + +typedef struct { + qemuNbdkitProcess *proc; + virDomainObj *vm; +} qemuNbdkitProcessEventData; + + +static qemuNbdkitProcessEventData* +qemuNbdkitProcessEventDataNew(qemuNbdkitProcess *proc, + virDomainObj *vm) +{ + qemuNbdkitProcessEventData *d =3D g_new(qemuNbdkitProcessEventData, 1); + d->proc =3D proc; + d->vm =3D virObjectRef(vm); + return d; +} + + +static void +qemuNbdkitProcessEventDataFree(qemuNbdkitProcessEventData *d) +{ + virObjectUnref(d->vm); + g_free(d); +} + + +#if WITH_DECL_SYS_PIDFD_OPEN +static void +qemuNbdkitProcessPidfdCb(int watch G_GNUC_UNUSED, + int fd, + int events G_GNUC_UNUSED, + void *opaque) +{ + qemuNbdkitProcessEventData *d =3D opaque; + + VIR_FORCE_CLOSE(fd); + VIR_DEBUG("nbdkit process %i died", d->proc->pid); + qemuNbdkitProcessRestart(d->proc, d->vm); +} +#else +static void +qemuNbdkitProcessTimeoutCb(int timer G_GNUC_UNUSED, + void *opaque) +{ + qemuNbdkitProcessEventData *d =3D opaque; + + if (virProcessKill(d->proc->pid, 0) < 0) { + VIR_DEBUG("nbdkit process %i died", d->proc->pid); + qemuNbdkitProcessRestart(d->proc, d->vm); + } +} +#endif /* WITH_DECL_SYS_PIDFD_OPEN */ + + +static int +qemuNbdkitProcessStartMonitor(qemuNbdkitProcess *proc, + virDomainObj *vm) +{ +#if WITH_DECL_SYS_PIDFD_OPEN + int pidfd; +#endif + +#if WITH_DECL_SYS_PIDFD_OPEN + pidfd =3D syscall(SYS_pidfd_open, proc->pid, 0); + if (pidfd < 0) + return -1; + + proc->eventwatch =3D virEventAddHandle(pidfd, + VIR_EVENT_HANDLE_READABLE, + qemuNbdkitProcessPidfdCb, + qemuNbdkitProcessEventDataNew(pro= c, vm), + (virFreeCallback)qemuNbdkitProces= sEventDataFree); +#else + /* fall back to checking once a second */ + proc->eventwatch =3D virEventAddTimeout(1000, + qemuNbdkitProcessTimeoutCb, + qemuNbdkitProcessEventDataNew(pr= oc, vm), + (virFreeCallback)qemuNbdkitProce= ssEventDataFree); +#endif /* WITH_DECL_SYS_PIDFD_OPEN */ + + if (proc->eventwatch < 0) + return -1; + + VIR_DEBUG("Monitoring nbdkit process %i for exit", proc->pid); + + return 0; +} + + +static void +qemuNbdkitProcessStopMonitor(qemuNbdkitProcess *proc) +{ + if (proc->eventwatch > 0) { +#if WITH_DECL_SYS_PIDFD_OPEN + virEventRemoveHandle(proc->eventwatch); +#else + virEventRemoveTimeout(proc->eventwatch); +#endif /* WITH_DECL_SYS_PIDFD_OPEN */ + proc->eventwatch =3D 0; + } +} + + static qemuNbdkitProcess * qemuNbdkitProcessNew(virStorageSource *source, const char *pidfile, @@ -660,9 +780,11 @@ qemuNbdkitReconnectStorageSource(virStorageSource *sou= rce, =20 =20 static void -qemuNbdkitStorageSourceManageProcessOne(virStorageSource *source) +qemuNbdkitStorageSourceManageProcessOne(virStorageSource *source, + virDomainObj *vm) { qemuDomainStorageSourcePrivate *srcpriv =3D QEMU_DOMAIN_STORAGE_SOURCE= _PRIVATE(source); + qemuDomainObjPrivate *vmpriv =3D vm->privateData; qemuNbdkitProcess *proc; =20 if (!srcpriv) @@ -673,6 +795,9 @@ qemuNbdkitStorageSourceManageProcessOne(virStorageSourc= e *source) if (!proc) return; =20 + if (!proc->caps) + proc->caps =3D qemuGetNbdkitCaps(vmpriv->driver); + if (proc->pid <=3D 0) { if (virPidFileReadPath(proc->pidfile, &proc->pid) < 0) { VIR_WARN("Unable to read pidfile '%s'", proc->pidfile); @@ -680,8 +805,14 @@ qemuNbdkitStorageSourceManageProcessOne(virStorageSour= ce *source) } } =20 - if (virProcessKill(proc->pid, 0) < 0) + if (virProcessKill(proc->pid, 0) < 0) { VIR_WARN("nbdkit process %i is not alive", proc->pid); + qemuNbdkitProcessRestart(proc, vm); + return; + } + + if (qemuNbdkitProcessStartMonitor(proc, vm) < 0) + VIR_WARN("unable monitor nbdkit process"); } =20 /** @@ -694,11 +825,12 @@ qemuNbdkitStorageSourceManageProcessOne(virStorageSou= rce *source) * disk and is attempting to re-connect to active domains. */ void -qemuNbdkitStorageSourceManageProcess(virStorageSource *source) +qemuNbdkitStorageSourceManageProcess(virStorageSource *source, + virDomainObj *vm) { virStorageSource *backing; for (backing =3D source; backing !=3D NULL; backing =3D backing->backi= ngStore) - qemuNbdkitStorageSourceManageProcessOne(backing); + qemuNbdkitStorageSourceManageProcessOne(backing, vm); } =20 =20 @@ -991,6 +1123,8 @@ qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc) void qemuNbdkitProcessFree(qemuNbdkitProcess *proc) { + qemuNbdkitProcessStopMonitor(proc); + g_clear_pointer(&proc->pidfile, g_free); g_clear_pointer(&proc->socketfile, g_free); g_clear_object(&proc->caps); @@ -1077,6 +1211,9 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, goto error; } =20 + if (qemuNbdkitProcessStartMonitor(proc, vm) < 0) + goto error; + return 0; =20 error: @@ -1098,6 +1235,8 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, int qemuNbdkitProcessStop(qemuNbdkitProcess *proc) { + qemuNbdkitProcessStopMonitor(proc); + if (proc->pid < 0) return 0; =20 diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h index 36a2219d82..326f3d5920 100644 --- a/src/qemu/qemu_nbdkit.h +++ b/src/qemu/qemu_nbdkit.h @@ -69,7 +69,8 @@ void qemuNbdkitStopStorageSource(virStorageSource *src); =20 void -qemuNbdkitStorageSourceManageProcess(virStorageSource *src); +qemuNbdkitStorageSourceManageProcess(virStorageSource *src, + virDomainObj *vm); =20 bool qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps, @@ -91,6 +92,7 @@ struct _qemuNbdkitProcess { uid_t user; gid_t group; pid_t pid; + int eventwatch; }; =20 int diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d0b797575d..390f1c2862 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9036,10 +9036,10 @@ qemuProcessReconnect(void *opaque) } =20 for (i =3D 0; i < obj->def->ndisks; i++) - qemuNbdkitStorageSourceManageProcess(obj->def->disks[i]->src); + qemuNbdkitStorageSourceManageProcess(obj->def->disks[i]->src, obj); =20 if (obj->def->os.loader && obj->def->os.loader->nvram) - qemuNbdkitStorageSourceManageProcess(obj->def->os.loader->nvram); + qemuNbdkitStorageSourceManageProcess(obj->def->os.loader->nvram, o= bj); =20 /* update domain state XML with possibly updated state in virDomainObj= */ if (virDomainObjSave(obj, driver->xmlopt, cfg->stateDir) < 0) --=20 2.39.1