[PATCH v4 4/8] qemu_domain: Introduce qemuDomainSchedCoreStart()

Michal Privoznik posted 8 patches 3 years, 4 months ago
[PATCH v4 4/8] qemu_domain: Introduce qemuDomainSchedCoreStart()
Posted by Michal Privoznik 3 years, 4 months ago
The aim of this helper function is to spawn a child process in
which new scheduling group is created. This dummy process will
then used to distribute scheduling group from (e.g. when starting
helper processes or QEMU itself). The process is not needed for
QEMU_SCHED_CORE_NONE case (obviously) nor for
QEMU_SCHED_CORE_VCPUS case (because in that case a slightly
different child will be forked off).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
---
 src/qemu/qemu_domain.c  | 105 ++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_domain.h  |  12 +++++
 src/qemu/qemu_process.c |   4 ++
 3 files changed, 121 insertions(+)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 858d14af6a..326ffdd335 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1778,6 +1778,8 @@ qemuDomainObjPrivateFree(void *data)
         g_object_unref(priv->eventThread);
     }
 
+    qemuDomainSchedCoreStop(priv);
+
     g_free(priv);
 }
 
@@ -1799,6 +1801,9 @@ qemuDomainObjPrivateAlloc(void *opaque)
     priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
     priv->driver = opaque;
 
+    priv->schedCoreChildPID = -1;
+    priv->schedCoreChildFD = -1;
+
     return g_steal_pointer(&priv);
 }
 
@@ -11771,3 +11776,103 @@ qemuDomainObjWait(virDomainObj *vm)
 
     return 0;
 }
+
+
+int
+qemuDomainSchedCoreStart(virQEMUDriverConfig *cfg,
+                         virDomainObj *vm)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    int waitfd[2] = { -1, -1 };
+    int syncfd[2] = { -1, -1 };
+    pid_t child = -1;
+
+    if (cfg->schedCore == QEMU_SCHED_CORE_NONE ||
+        cfg->schedCore == QEMU_SCHED_CORE_VCPUS) {
+        /* We don't need any dummy process for any of these two variants. */
+        return 0;
+    }
+
+    if (virPipe(waitfd) < 0 ||
+        virPipe(syncfd) < 0)
+        return -1;
+
+    if ((child = virFork()) < 0)
+        goto error;
+
+    if (child == 0) {
+        /* child */
+        int rc;
+        char c;
+
+        VIR_FORCE_CLOSE(waitfd[1]);
+        VIR_FORCE_CLOSE(syncfd[0]);
+
+        errno = 0;
+        rc = virProcessSchedCoreCreate();
+        c = errno;
+        ignore_value(safewrite(syncfd[1], &c, 1));
+        VIR_FORCE_CLOSE(syncfd[1]);
+
+        if (rc < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Unable to set SCHED_CORE"));
+            _exit(EXIT_FAILURE);
+        }
+
+        ignore_value(saferead(waitfd[0], &c, 1));
+        VIR_FORCE_CLOSE(waitfd[0]);
+        _exit(EXIT_SUCCESS);
+    } else {
+        /* parent */
+        char c = '\0';
+        VIR_FORCE_CLOSE(waitfd[0]);
+        VIR_FORCE_CLOSE(syncfd[1]);
+
+        if (saferead(syncfd[0], &c, 1) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("unable to read from pipe"));
+            goto error;
+        }
+        VIR_FORCE_CLOSE(syncfd[0]);
+
+        if (c != 0) {
+            virReportSystemError(c, "%s",
+                                 _("Unable to set SCHED_CORE"));
+            goto error;
+        }
+
+        VIR_DEBUG("Spawned dummy process for schedCore (%s) pid=%lld fd=%d",
+                  virQEMUSchedCoreTypeToString(cfg->schedCore),
+                  (long long) child, waitfd[1]);
+
+        priv->schedCoreChildPID = child;
+        priv->schedCoreChildFD = waitfd[1];
+    }
+
+    return 0;
+
+ error:
+    VIR_FORCE_CLOSE(waitfd[0]);
+    VIR_FORCE_CLOSE(waitfd[1]);
+    VIR_FORCE_CLOSE(syncfd[0]);
+    VIR_FORCE_CLOSE(syncfd[1]);
+    return -1;
+}
+
+
+void
+qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv)
+{
+    if (priv->schedCoreChildFD != -1) {
+        ignore_value(safewrite(priv->schedCoreChildFD, "q", 1));
+        VIR_FORCE_CLOSE(priv->schedCoreChildFD);
+    }
+
+    if (priv->schedCoreChildPID != -1) {
+        VIR_DEBUG("Killing dummy procces for schedCore pid=%lld",
+                  (long long) priv->schedCoreChildPID);
+        virProcessAbort(priv->schedCoreChildPID);
+        priv->schedCoreChildPID = -1;
+    }
+}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index a22deaf113..d86ef5f3d6 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -242,6 +242,11 @@ struct _qemuDomainObjPrivate {
 
     unsigned long long originalMemlock; /* Original RLIMIT_MEMLOCK, zero if no
                                          * restore will be required later */
+
+    /* Info on dummy process for schedCore. A short lived process used only
+     * briefly when starting a guest. Don't save/parse into XML. */
+    pid_t schedCoreChildPID;
+    pid_t schedCoreChildFD;
 };
 
 #define QEMU_DOMAIN_PRIVATE(vm) \
@@ -1098,3 +1103,10 @@ qemuDomainRemoveLogs(virQEMUDriver *driver,
 
 int
 qemuDomainObjWait(virDomainObj *vm);
+
+int
+qemuDomainSchedCoreStart(virQEMUDriverConfig *cfg,
+                         virDomainObj *vm);
+
+void
+qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 97336e2622..7385f9fb28 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7485,6 +7485,9 @@ qemuProcessLaunch(virConnectPtr conn,
     if (qemuProcessGenID(vm, flags) < 0)
         goto cleanup;
 
+    if (qemuDomainSchedCoreStart(cfg, vm) < 0)
+        goto cleanup;
+
     if (qemuExtDevicesStart(driver, vm, incoming != NULL) < 0)
         goto cleanup;
 
@@ -7757,6 +7760,7 @@ qemuProcessLaunch(virConnectPtr conn,
     ret = 0;
 
  cleanup:
+    qemuDomainSchedCoreStop(priv);
     qemuDomainSecretDestroy(vm);
     return ret;
 }
-- 
2.35.1
Re: [PATCH v4 4/8] qemu_domain: Introduce qemuDomainSchedCoreStart()
Posted by Daniel P. Berrangé 3 years, 3 months ago
On Thu, Oct 06, 2022 at 03:49:46PM +0200, Michal Privoznik wrote:
> The aim of this helper function is to spawn a child process in
> which new scheduling group is created. This dummy process will
> then used to distribute scheduling group from (e.g. when starting
> helper processes or QEMU itself). The process is not needed for
> QEMU_SCHED_CORE_NONE case (obviously) nor for
> QEMU_SCHED_CORE_VCPUS case (because in that case a slightly
> different child will be forked off).
> 
> Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
> ---
>  src/qemu/qemu_domain.c  | 105 ++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_domain.h  |  12 +++++
>  src/qemu/qemu_process.c |   4 ++
>  3 files changed, 121 insertions(+)

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|