From nobody Tue Dec 16 08:05:26 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1524489326749703.2337370264078; Mon, 23 Apr 2018 06:15:26 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DD8243182F5D; Mon, 23 Apr 2018 13:15:24 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5BC04173D9; Mon, 23 Apr 2018 13:15:24 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 0DC4465D13; Mon, 23 Apr 2018 13:15:24 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w3NDF2Tq022119 for ; Mon, 23 Apr 2018 09:15:02 -0400 Received: by smtp.corp.redhat.com (Postfix) id 6024B215CDC8; Mon, 23 Apr 2018 13:15:02 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id BC678215CDCE; Mon, 23 Apr 2018 13:15:01 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Mon, 23 Apr 2018 15:14:43 +0200 Message-Id: <01f9387202041ca4093893a98726be3d3baafebc.1524489077.git.mprivozn@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-loop: libvir-list@redhat.com Cc: pkrempa@redhat.com Subject: [libvirt] [PATCH v5 08/11] qemu: Start PR daemon on domain startup X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.49]); Mon, 23 Apr 2018 13:15:25 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Before we exec() qemu we have to spawn pr-helper processes for all managed reservations (well, technically there can only one). The only caveat there is that we should place the process into the same namespace and cgroup as qemu (so that it shares the same view of the system). But we can do that only after we've forked. That means calling the setup function between fork() and exec(). Again, despite demand to not store anything in status XML I have to take my chances and store 'priv->prDaemonRunning' (at least) in status XML. Otherwise we might forget whether we started pr-helper after libvirtd restart. What happens if we change default managed alias or default socket is undefined for now, because we don't store them in status XML. Signed-off-by: Michal Privoznik Reviewed-by: John Ferlan --- src/qemu/qemu_domain.c | 22 +++++ src/qemu/qemu_domain.h | 2 + src/qemu/qemu_process.c | 232 ++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 256 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 5ccdeb8e3a..fbe6a0f332 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2040,6 +2040,15 @@ qemuDomainObjPrivateXMLFormatAllowReboot(virBufferPt= r buf, } =20 =20 +static void +qemuDomainObjPrivateXMLFormatPR(virBufferPtr buf, + qemuDomainObjPrivatePtr priv) +{ + if (priv->prDaemonRunning) + virBufferAddLit(buf, "\n"); +} + + static int qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, virDomainObjPtr vm, @@ -2180,6 +2189,8 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, =20 qemuDomainObjPrivateXMLFormatAllowReboot(buf, priv->allowReboot); =20 + qemuDomainObjPrivateXMLFormatPR(buf, priv); + if (qemuDomainObjPrivateXMLFormatBlockjobs(buf, vm) < 0) return -1; =20 @@ -2323,6 +2334,15 @@ qemuDomainObjPrivateXMLParseAllowReboot(xmlXPathCont= extPtr ctxt, } =20 =20 +static void +qemuDomainObjPrivateXMLParsePR(xmlXPathContextPtr ctxt, + bool *prDaemonRunning) +{ + *prDaemonRunning =3D virXPathBoolean("count(./prDaemon[@running =3D '1= ']) > 0", + ctxt) > 0; +} + + static int qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, qemuDomainObjPrivatePtr priv, @@ -2572,6 +2592,8 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, =20 qemuDomainObjPrivateXMLParseAllowReboot(ctxt, &priv->allowReboot); =20 + qemuDomainObjPrivateXMLParsePR(ctxt, &priv->prDaemonRunning); + if (qemuDomainObjPrivateXMLParseBlockjobs(priv, ctxt) < 0) goto error; =20 diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 612d234113..b837902e8d 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -342,6 +342,8 @@ struct _qemuDomainObjPrivate { /* Migration capabilities. Rechecked on reconnect, not to be saved in * private XML. */ virBitmapPtr migrationCaps; + + bool prDaemonRunning; }; =20 # define QEMU_DOMAIN_PRIVATE(vm) \ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6a5262ae46..36cfa438ed 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2555,6 +2555,231 @@ qemuProcessResctrlCreate(virQEMUDriverPtr driver, } =20 =20 +static char * +qemuProcessBuildPRHelperPidfilePath(virDomainObjPtr vm, + const char *prdAlias) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + + return virPidFileBuildPath(priv->libDir, prdAlias); +} + + +static void +qemuProcessKillPRDaemon(virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virErrorPtr orig_err; + const char *prdAlias; + char *pidfile; + + if (!priv->prDaemonRunning) + return; + + if (!(prdAlias =3D qemuDomainGetManagedPRAlias())) { + VIR_WARN("Unable to get default PR manager alias"); + return; + } + + if (!(pidfile =3D qemuProcessBuildPRHelperPidfilePath(vm, prdAlias))) { + VIR_WARN("Unable to construct pr-helper pidfile path"); + return; + } + + virErrorPreserveLast(&orig_err); + if (virPidFileForceCleanupPath(pidfile) < 0) { + VIR_WARN("Unable to kill pr-helper process"); + } else { + if (unlink(pidfile) < 0 && + errno !=3D ENOENT) { + virReportSystemError(errno, + _("Unable to remove stale pidfile %s"), + pidfile); + } else { + priv->prDaemonRunning =3D false; + } + } + virErrorRestore(&orig_err); + + VIR_FREE(pidfile); +} + + +static int +qemuProcessStartPRDaemonHook(void *opaque) +{ + virDomainObjPtr vm =3D opaque; + size_t i, nfds =3D 0; + int *fds =3D NULL; + int ret =3D -1; + + if (virProcessGetNamespaces(vm->pid, &nfds, &fds) < 0) + return ret; + + if (nfds > 0 && + virProcessSetNamespaces(nfds, fds) < 0) + goto cleanup; + + ret =3D 0; + cleanup: + for (i =3D 0; i < nfds; i++) + VIR_FORCE_CLOSE(fds[i]); + VIR_FREE(fds); + return ret; +} + + +static int +qemuProcessStartPRDaemon(virDomainObjPtr vm, + const virDomainDiskDef *disk) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virQEMUDriverPtr driver =3D priv->driver; + virQEMUDriverConfigPtr cfg; + const char *prdAlias; + int errfd =3D -1; + char *pidfile =3D NULL; + int pidfd =3D -1; + char *socketPath =3D NULL; + pid_t cpid =3D -1; + virCommandPtr cmd =3D NULL; + virTimeBackOffVar timebackoff; + const unsigned long long timeout =3D 500000; /* ms */ + int ret =3D -1; + + if (!virStoragePRDefIsManaged(disk->src->pr) || + priv->prDaemonRunning) + return 0; + + cfg =3D virQEMUDriverGetConfig(driver); + + if (!virFileIsExecutable(cfg->prHelperName)) { + virReportSystemError(errno, _("'%s' is not a suitable pr helper"), + cfg->prHelperName); + goto cleanup; + } + + prdAlias =3D qemuDomainGetManagedPRAlias(); + + if (!(pidfile =3D qemuProcessBuildPRHelperPidfilePath(vm, prdAlias))) + goto cleanup; + + /* Just try to acquire. Dummy pid will be replaced later */ + if ((pidfd =3D virPidFileAcquirePath(pidfile, false, -1)) < 0) + goto cleanup; + + if (!(socketPath =3D qemuDomainGetPRSocketPath(vm, disk->src->pr))) + goto cleanup; + + /* Remove stale socket */ + if (unlink(socketPath) < 0 && + errno !=3D ENOENT) { + virReportSystemError(errno, + _("Unable to remove stale socket path: %s"), + socketPath); + goto cleanup; + } + + if (!(cmd =3D virCommandNewArgList(cfg->prHelperName, + "-k", socketPath, + "-f", pidfile, + NULL))) + goto cleanup; + + virCommandDaemonize(cmd); + /* We want our virCommand to write child PID into the pidfile + * so that we can read it even before exec(). */ + virCommandSetPidFile(cmd, pidfile); + virCommandSetErrorFD(cmd, &errfd); + + /* Place the process into the same namespace and cgroup as + * qemu (so that it shares the same view of the system). */ + virCommandSetPreExecHook(cmd, qemuProcessStartPRDaemonHook, vm); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + if (virPidFileReadPath(pidfile, &cpid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("pr helper %s didn't show up"), prdAlias); + goto cleanup; + } + + if (virTimeBackOffStart(&timebackoff, 1, timeout) < 0) + goto cleanup; + while (virTimeBackOffWait(&timebackoff)) { + char errbuf[1024] =3D { 0 }; + + if (virFileExists(socketPath)) + break; + + if (virProcessKill(cpid, 0) =3D=3D 0) + continue; + + if (saferead(errfd, errbuf, sizeof(errbuf) - 1) < 0) { + virReportSystemError(errno, + _("pr helper %s died unexpectedly"), prdA= lias); + } else { + virReportError(VIR_ERR_OPERATION_FAILED, + _("pr helper died and reported: %s"), errbuf); + } + goto cleanup; + } + + if (!virFileExists(socketPath)) { + virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s", + _("pr helper socked did not show up")); + goto cleanup; + } + + if (priv->cgroup && + virCgroupAddMachineTask(priv->cgroup, cpid) < 0) + goto cleanup; + + if (qemuSecurityDomainSetPathLabel(driver->securityManager, + vm->def, socketPath, true) < 0) + goto cleanup; + + priv->prDaemonRunning =3D true; + ret =3D 1; + cleanup: + if (ret < 0) { + virCommandAbort(cmd); + if (cpid >=3D 0) + virProcessKillPainfully(cpid, true); + if (pidfile) + unlink(pidfile); + } + virCommandFree(cmd); + VIR_FREE(socketPath); + VIR_FORCE_CLOSE(pidfd); + VIR_FREE(pidfile); + VIR_FORCE_CLOSE(errfd); + virObjectUnref(cfg); + return ret; +} + + +static int +qemuProcessMaybeStartPRDaemon(virDomainObjPtr vm) +{ + size_t i; + int rv; + + for (i =3D 0; i < vm->def->ndisks; i++) { + const virDomainDiskDef *disk =3D vm->def->disks[i]; + + if ((rv =3D qemuProcessStartPRDaemon(vm, disk)) < 0) + return -1; + + if (rv > 0) + return 1; + } + + return 0; +} + + static int qemuProcessInitPasswords(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -6071,6 +6296,10 @@ qemuProcessLaunch(virConnectPtr conn, if (qemuProcessResctrlCreate(driver, vm) < 0) goto cleanup; =20 + VIR_DEBUG("Setting up PR daemon"); + if (qemuProcessMaybeStartPRDaemon(vm) < 0) + goto cleanup; + VIR_DEBUG("Setting domain security labels"); if (qemuSecuritySetAllLabel(driver, vm, @@ -6598,6 +6827,9 @@ void qemuProcessStop(virQEMUDriverPtr driver, /* Remove the master key */ qemuDomainMasterKeyRemove(priv); =20 + /* Do this before we delete the tree and remove pidfile. */ + qemuProcessKillPRDaemon(vm); + virFileDeleteTree(priv->libDir); virFileDeleteTree(priv->channelTargetDir); =20 --=20 2.16.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list