1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-25 01:34:11 +03:00

qemu: cgroup: Extract temporary relaxing of cgroup setting for vcpu hotplug

When hot-adding vcpus qemu needs to allocate some structures in the DMA
zone which may be outside of the numa pinning. Extract the code doing
this in a set of helpers so that it can be reused.
This commit is contained in:
Peter Krempa 2016-09-07 13:11:59 +02:00
parent e2c63714a8
commit eb5dee3534
3 changed files with 105 additions and 32 deletions

View File

@ -1127,3 +1127,93 @@ qemuRemoveCgroup(virDomainObjPtr vm)
return virCgroupRemove(priv->cgroup);
}
static void
qemuCgroupEmulatorAllNodesDataFree(qemuCgroupEmulatorAllNodesDataPtr data)
{
if (!data)
return;
virCgroupFree(&data->emulatorCgroup);
VIR_FREE(data->emulatorMemMask);
VIR_FREE(data);
}
/**
* qemuCgroupEmulatorAllNodesAllow:
* @cgroup: domain cgroup pointer
* @retData: filled with structure used to roll back the operation
*
* Allows all NUMA nodes for the qemu emulator thread temporarily. This is
* necessary when hotplugging cpus since it requires memory allocated in the
* DMA region. Afterwards the operation can be reverted by
* qemuCgrouEmulatorAllNodesRestore.
*
* Returns 0 on success -1 on error
*/
int
qemuCgroupEmulatorAllNodesAllow(virCgroupPtr cgroup,
qemuCgroupEmulatorAllNodesDataPtr *retData)
{
qemuCgroupEmulatorAllNodesDataPtr data = NULL;
char *all_nodes_str = NULL;
virBitmapPtr all_nodes = NULL;
int ret = -1;
if (!virNumaIsAvailable() ||
!virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET))
return 0;
if (!(all_nodes = virNumaGetHostNodeset()))
goto cleanup;
if (!(all_nodes_str = virBitmapFormat(all_nodes)))
goto cleanup;
if (VIR_ALLOC(data) < 0)
goto cleanup;
if (virCgroupNewThread(cgroup, VIR_CGROUP_THREAD_EMULATOR, 0,
false, &data->emulatorCgroup) < 0)
goto cleanup;
if (virCgroupGetCpusetMems(data->emulatorCgroup, &data->emulatorMemMask) < 0 ||
virCgroupSetCpusetMems(data->emulatorCgroup, all_nodes_str) < 0)
goto cleanup;
VIR_STEAL_PTR(*retData, data);
ret = 0;
cleanup:
VIR_FREE(all_nodes_str);
virBitmapFree(all_nodes);
qemuCgroupEmulatorAllNodesDataFree(data);
return ret;
}
/**
* qemuCgrouEmulatorAllNodesRestore:
* @data: data structure created by qemuCgroupEmulatorAllNodesAllow
*
* Rolls back the setting done by qemuCgroupEmulatorAllNodesAllow and frees the
* associated data.
*/
void
qemuCgrouEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data)
{
virErrorPtr err;
if (!data)
return;
err = virSaveLastError();
virCgroupSetCpusetMems(data->emulatorCgroup, data->emulatorMemMask);
virSetError(err);
virFreeError(err);
qemuCgroupEmulatorAllNodesDataFree(data);
}

View File

@ -57,4 +57,15 @@ int qemuSetupCgroupCpusetCpus(virCgroupPtr cgroup, virBitmapPtr cpumask);
int qemuSetupGlobalCpuCgroup(virDomainObjPtr vm);
int qemuRemoveCgroup(virDomainObjPtr vm);
typedef struct _qemuCgroupEmulatorAllNodesData qemuCgroupEmulatorAllNodesData;
typedef qemuCgroupEmulatorAllNodesData *qemuCgroupEmulatorAllNodesDataPtr;
struct _qemuCgroupEmulatorAllNodesData {
virCgroupPtr emulatorCgroup;
char *emulatorMemMask;
};
int qemuCgroupEmulatorAllNodesAllow(virCgroupPtr cgroup,
qemuCgroupEmulatorAllNodesDataPtr *data);
void qemuCgrouEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data);
#endif /* __QEMU_CGROUP_H__ */

View File

@ -4853,11 +4853,7 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
unsigned int nvcpus)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup_temp = NULL;
char *mem_mask = NULL;
char *all_nodes_str = NULL;
virBitmapPtr all_nodes = NULL;
virErrorPtr err = NULL;
qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL;
virBitmapPtr vcpumap = NULL;
ssize_t nextvcpu = -1;
int rc = 0;
@ -4866,22 +4862,8 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus)))
goto cleanup;
if (virNumaIsAvailable() &&
virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, 0,
false, &cgroup_temp) < 0)
goto cleanup;
if (!(all_nodes = virNumaGetHostNodeset()))
goto cleanup;
if (!(all_nodes_str = virBitmapFormat(all_nodes)))
goto cleanup;
if (virCgroupGetCpusetMems(cgroup_temp, &mem_mask) < 0 ||
virCgroupSetCpusetMems(cgroup_temp, all_nodes_str) < 0)
goto cleanup;
}
if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0)
goto cleanup;
if (nvcpus > virDomainDefGetVcpus(vm->def)) {
while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) {
@ -4909,17 +4891,7 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
ret = 0;
cleanup:
if (mem_mask) {
err = virSaveLastError();
virCgroupSetCpusetMems(cgroup_temp, mem_mask);
virSetError(err);
virFreeError(err);
VIR_FREE(mem_mask);
}
VIR_FREE(all_nodes_str);
virBitmapFree(all_nodes);
virCgroupFree(&cgroup_temp);
qemuCgrouEmulatorAllNodesRestore(emulatorCgroup);
virBitmapFree(vcpumap);
return ret;