mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
qemu: Add support to pin IOThreads to specific CPU
Add qemuDomainPinIOThread to handle setting the CPU affinity for a specific IOThread
This commit is contained in:
parent
e878719117
commit
fb562614e3
@ -3217,6 +3217,15 @@ typedef void (*virConnectDomainEventDeviceRemovedCallback)(virConnectPtr conn,
|
|||||||
*/
|
*/
|
||||||
# define VIR_DOMAIN_TUNABLE_CPU_EMULATORPIN "cputune.emulatorpin"
|
# define VIR_DOMAIN_TUNABLE_CPU_EMULATORPIN "cputune.emulatorpin"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VIR_DOMAIN_TUNABLE_CPU_IOTHREADSPIN:
|
||||||
|
*
|
||||||
|
* Macro represents formatted pinning for one IOThread specified by id which is
|
||||||
|
* appended to the parameter name, for example "cputune.iothreadpin1",
|
||||||
|
* as VIR_TYPED_PARAM_STRING.
|
||||||
|
*/
|
||||||
|
# define VIR_DOMAIN_TUNABLE_CPU_IOTHREADSPIN "cputune.iothreadpin%u"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VIR_DOMAIN_TUNABLE_CPU_CPU_SHARES:
|
* VIR_DOMAIN_TUNABLE_CPU_CPU_SHARES:
|
||||||
*
|
*
|
||||||
|
@ -5759,6 +5759,206 @@ qemuDomainGetIOThreadsInfo(virDomainPtr dom,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainPinIOThread(virDomainPtr dom,
|
||||||
|
unsigned int iothread_id,
|
||||||
|
unsigned char *cpumap,
|
||||||
|
int maplen,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
virQEMUDriverPtr driver = dom->conn->privateData;
|
||||||
|
virQEMUDriverConfigPtr cfg = NULL;
|
||||||
|
virDomainObjPtr vm;
|
||||||
|
virCapsPtr caps = NULL;
|
||||||
|
virDomainDefPtr persistentDef = NULL;
|
||||||
|
virBitmapPtr pcpumap = NULL;
|
||||||
|
qemuDomainObjPrivatePtr priv;
|
||||||
|
virDomainVcpuPinDefPtr *newIOThreadsPin = NULL;
|
||||||
|
size_t newIOThreadsPinNum = 0;
|
||||||
|
virCgroupPtr cgroup_iothread = NULL;
|
||||||
|
virObjectEventPtr event = NULL;
|
||||||
|
char paramField[VIR_TYPED_PARAM_FIELD_LENGTH] = "";
|
||||||
|
char *str = NULL;
|
||||||
|
virTypedParameterPtr eventParams = NULL;
|
||||||
|
int eventNparams = 0;
|
||||||
|
int eventMaxparams = 0;
|
||||||
|
|
||||||
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
||||||
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
||||||
|
|
||||||
|
cfg = virQEMUDriverGetConfig(driver);
|
||||||
|
|
||||||
|
if (!(vm = qemuDomObjFromDomain(dom)))
|
||||||
|
goto cleanup;
|
||||||
|
priv = vm->privateData;
|
||||||
|
|
||||||
|
if (virDomainPinIOThreadEnsureACL(dom->conn, vm->def, flags) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
|
||||||
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
||||||
|
_("Changing affinity for IOThread dynamically is "
|
||||||
|
"not allowed when CPU placement is 'auto'"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
|
||||||
|
&persistentDef) < 0)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
if (!(pcpumap = virBitmapNewData(cpumap, maplen)))
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
if (virBitmapIsAllClear(pcpumap)) {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
|
_("Empty iothread cpumap list for pinning"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
||||||
|
|
||||||
|
if (priv->iothreadpids == NULL) {
|
||||||
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s", _("IOThread affinity is not supported"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iothread_id > priv->niothreadpids) {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("iothread value out of range %d > %d"),
|
||||||
|
iothread_id, priv->niothreadpids);
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->def->cputune.iothreadspin) {
|
||||||
|
/* The VcpuPinDefCopy works for IOThreads too */
|
||||||
|
newIOThreadsPin =
|
||||||
|
virDomainVcpuPinDefCopy(vm->def->cputune.iothreadspin,
|
||||||
|
vm->def->cputune.niothreadspin);
|
||||||
|
if (!newIOThreadsPin)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
newIOThreadsPinNum = vm->def->cputune.niothreadspin;
|
||||||
|
} else {
|
||||||
|
if (VIR_ALLOC(newIOThreadsPin) < 0)
|
||||||
|
goto endjob;
|
||||||
|
newIOThreadsPinNum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virDomainIOThreadsPinAdd(&newIOThreadsPin, &newIOThreadsPinNum,
|
||||||
|
cpumap, maplen, iothread_id) < 0) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("failed to update iothreadspin"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure the corresponding cpuset cgroup before set affinity. */
|
||||||
|
if (virCgroupHasController(priv->cgroup,
|
||||||
|
VIR_CGROUP_CONTROLLER_CPUSET)) {
|
||||||
|
if (virCgroupNewIOThread(priv->cgroup, iothread_id,
|
||||||
|
false, &cgroup_iothread) < 0)
|
||||||
|
goto endjob;
|
||||||
|
if (qemuSetupCgroupIOThreadsPin(cgroup_iothread,
|
||||||
|
newIOThreadsPin,
|
||||||
|
newIOThreadsPinNum,
|
||||||
|
iothread_id) < 0) {
|
||||||
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
_("failed to set cpuset.cpus in cgroup"
|
||||||
|
" for iothread %d"), iothread_id);
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (virProcessSetAffinity(priv->iothreadpids[iothread_id - 1],
|
||||||
|
pcpumap) < 0) {
|
||||||
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
|
_("failed to set cpu affinity for IOThread %d"),
|
||||||
|
iothread_id);
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->def->cputune.iothreadspin)
|
||||||
|
virDomainVcpuPinDefArrayFree(vm->def->cputune.iothreadspin,
|
||||||
|
vm->def->cputune.niothreadspin);
|
||||||
|
|
||||||
|
vm->def->cputune.iothreadspin = newIOThreadsPin;
|
||||||
|
vm->def->cputune.niothreadspin = newIOThreadsPinNum;
|
||||||
|
newIOThreadsPin = NULL;
|
||||||
|
|
||||||
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
if (snprintf(paramField, VIR_TYPED_PARAM_FIELD_LENGTH,
|
||||||
|
VIR_DOMAIN_TUNABLE_CPU_IOTHREADSPIN, iothread_id) < 0) {
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = virBitmapFormat(pcpumap);
|
||||||
|
if (virTypedParamsAddString(&eventParams, &eventNparams,
|
||||||
|
&eventMaxparams, paramField, str) < 0)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
event = virDomainEventTunableNewFromDom(dom, eventParams, eventNparams);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
||||||
|
/* Coverity didn't realize that targetDef must be set if we got here. */
|
||||||
|
sa_assert(persistentDef);
|
||||||
|
|
||||||
|
if (iothread_id > persistentDef->iothreads) {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("iothread value out of range %d > %d"),
|
||||||
|
iothread_id, persistentDef->iothreads);
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!persistentDef->cputune.iothreadspin) {
|
||||||
|
if (VIR_ALLOC(persistentDef->cputune.iothreadspin) < 0)
|
||||||
|
goto endjob;
|
||||||
|
persistentDef->cputune.niothreadspin = 0;
|
||||||
|
}
|
||||||
|
if (virDomainIOThreadsPinAdd(&persistentDef->cputune.iothreadspin,
|
||||||
|
&persistentDef->cputune.niothreadspin,
|
||||||
|
cpumap,
|
||||||
|
maplen,
|
||||||
|
iothread_id) < 0) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("failed to update or add iothreadspin xml "
|
||||||
|
"of a persistent domain"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = virDomainSaveConfig(cfg->configDir, persistentDef);
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
endjob:
|
||||||
|
qemuDomainObjEndJob(driver, vm);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (newIOThreadsPin)
|
||||||
|
virDomainVcpuPinDefArrayFree(newIOThreadsPin, newIOThreadsPinNum);
|
||||||
|
if (cgroup_iothread)
|
||||||
|
virCgroupFree(&cgroup_iothread);
|
||||||
|
if (event)
|
||||||
|
qemuDomainEventQueue(driver, event);
|
||||||
|
VIR_FREE(str);
|
||||||
|
virBitmapFree(pcpumap);
|
||||||
|
qemuDomObjEndAPI(&vm);
|
||||||
|
virObjectUnref(caps);
|
||||||
|
virObjectUnref(cfg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
|
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
|
||||||
{
|
{
|
||||||
virQEMUDriverPtr driver = dom->conn->privateData;
|
virQEMUDriverPtr driver = dom->conn->privateData;
|
||||||
@ -19282,6 +19482,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
|
|||||||
.domainGetVcpus = qemuDomainGetVcpus, /* 0.4.4 */
|
.domainGetVcpus = qemuDomainGetVcpus, /* 0.4.4 */
|
||||||
.domainGetMaxVcpus = qemuDomainGetMaxVcpus, /* 0.4.4 */
|
.domainGetMaxVcpus = qemuDomainGetMaxVcpus, /* 0.4.4 */
|
||||||
.domainGetIOThreadsInfo = qemuDomainGetIOThreadsInfo, /* 1.2.14 */
|
.domainGetIOThreadsInfo = qemuDomainGetIOThreadsInfo, /* 1.2.14 */
|
||||||
|
.domainPinIOThread = qemuDomainPinIOThread, /* 1.2.14 */
|
||||||
.domainGetSecurityLabel = qemuDomainGetSecurityLabel, /* 0.6.1 */
|
.domainGetSecurityLabel = qemuDomainGetSecurityLabel, /* 0.6.1 */
|
||||||
.domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
|
.domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
|
||||||
.nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
|
.nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
|
||||||
|
Loading…
Reference in New Issue
Block a user