qemu_domain: Introduce qemuDomainSchedCoreStart()

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>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Michal Privoznik 2022-08-10 17:17:42 +02:00
parent 6a1500b4ea
commit 4be75216be
3 changed files with 121 additions and 0 deletions

View File

@ -1783,6 +1783,8 @@ qemuDomainObjPrivateFree(void *data)
if (priv->statsSchema)
g_clear_pointer(&priv->statsSchema, g_hash_table_destroy);
qemuDomainSchedCoreStop(priv);
g_free(priv);
}
@ -1806,6 +1808,9 @@ qemuDomainObjPrivateAlloc(void *opaque)
priv->statsSchema = NULL;
priv->schedCoreChildPID = -1;
priv->schedCoreChildFD = -1;
return g_steal_pointer(&priv);
}
@ -12070,3 +12075,103 @@ qemuDomainSyncRxFilter(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;
}
}

View File

@ -244,6 +244,11 @@ struct _qemuDomainObjPrivate {
* restore will be required later */
GHashTable *statsSchema; /* (name, data) pair for stats */
/* 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) \
@ -1108,3 +1113,10 @@ int
qemuDomainSyncRxFilter(virDomainObj *vm,
virDomainNetDef *def,
virDomainAsyncJob asyncJob);
int
qemuDomainSchedCoreStart(virQEMUDriverConfig *cfg,
virDomainObj *vm);
void
qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv);

View File

@ -7479,6 +7479,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;
@ -7751,6 +7754,7 @@ qemuProcessLaunch(virConnectPtr conn,
ret = 0;
cleanup:
qemuDomainSchedCoreStop(priv);
qemuDomainSecretDestroy(vm);
return ret;
}