mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 19:32:19 +00:00
Support memory ballooning in QEMU
This commit is contained in:
parent
97230f6a35
commit
cb7593bd19
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
|||||||
|
Fri Mar 27 11:44:22 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
|
Support memory ballooning in QEMU
|
||||||
|
* src/qemu_conf.c: Fix initial QEMU startup memory allocation
|
||||||
|
to be based on 'max memory'
|
||||||
|
* src/qemu_driver.c: Balloon down allocation to 'memory'
|
||||||
|
setting at startup. Implement virDomainSetMemory() for running
|
||||||
|
guests via memory balloon. Report mem current usage by querying
|
||||||
|
memory balloon.
|
||||||
|
|
||||||
Tue Mar 24 11:14:22 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
Tue Mar 24 11:14:22 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* src/capabilities.c, file src/capabilities.h,
|
* src/capabilities.c, file src/capabilities.h,
|
||||||
|
@ -927,7 +927,11 @@ int qemudBuildCommandLine(virConnectPtr conn,
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024);
|
/* Set '-m MB' based on maxmem, because the lower 'memory' limit
|
||||||
|
* is set post-startup using the balloon driver. If balloon driver
|
||||||
|
* is not supported, then they're out of luck anyway
|
||||||
|
*/
|
||||||
|
snprintf(memory, sizeof(memory), "%lu", vm->def->maxmem/1024);
|
||||||
snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus);
|
snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus);
|
||||||
snprintf(domid, sizeof(domid), "%d", vm->def->id);
|
snprintf(domid, sizeof(domid), "%d", vm->def->id);
|
||||||
pidfile = virFilePid(driver->stateDir, vm->def->name);
|
pidfile = virFilePid(driver->stateDir, vm->def->name);
|
||||||
|
@ -122,6 +122,9 @@ static int qemudMonitorCommandExtra(const virDomainObjPtr vm,
|
|||||||
const char *extra,
|
const char *extra,
|
||||||
const char *extraPrompt,
|
const char *extraPrompt,
|
||||||
char **reply);
|
char **reply);
|
||||||
|
static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned long newmem);
|
||||||
|
|
||||||
static struct qemud_driver *qemu_driver = NULL;
|
static struct qemud_driver *qemu_driver = NULL;
|
||||||
|
|
||||||
@ -1481,6 +1484,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
|
|||||||
(qemudDetectVcpuPIDs(conn, vm) < 0) ||
|
(qemudDetectVcpuPIDs(conn, vm) < 0) ||
|
||||||
(qemudInitCpus(conn, vm, migrateFrom) < 0) ||
|
(qemudInitCpus(conn, vm, migrateFrom) < 0) ||
|
||||||
(qemudInitPasswords(conn, driver, vm) < 0) ||
|
(qemudInitPasswords(conn, driver, vm) < 0) ||
|
||||||
|
(qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) ||
|
||||||
(qemudSaveDomainStatus(conn, qemu_driver, vm) < 0)) {
|
(qemudSaveDomainStatus(conn, qemu_driver, vm) < 0)) {
|
||||||
qemudShutdownVMDaemon(conn, driver, vm);
|
qemudShutdownVMDaemon(conn, driver, vm);
|
||||||
return -1;
|
return -1;
|
||||||
@ -2410,6 +2414,95 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */
|
||||||
|
#define BALLOON_PREFIX "balloon: actual="
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns: 0 if balloon not supported, +1 if balloon query worked
|
||||||
|
* or -1 on failure
|
||||||
|
*/
|
||||||
|
static int qemudDomainGetMemoryBalloon(virConnectPtr conn,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned long *currmem) {
|
||||||
|
char *reply = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
char *offset;
|
||||||
|
|
||||||
|
if (qemudMonitorCommand(vm, "info balloon", &reply) < 0) {
|
||||||
|
qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
||||||
|
"%s", _("could not query memory balloon allocation"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ("balloon reply: '%s'", reply);
|
||||||
|
if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) {
|
||||||
|
unsigned int memMB;
|
||||||
|
char *end;
|
||||||
|
offset += strlen(BALLOON_PREFIX);
|
||||||
|
if (virStrToLong_ui(offset, &end, 10, &memMB) < 0) {
|
||||||
|
qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
||||||
|
"%s", _("could not parse memory balloon allocation"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
*currmem = memMB * 1024;
|
||||||
|
ret = 1;
|
||||||
|
} else {
|
||||||
|
/* We don't raise an error here, since its to be expected that
|
||||||
|
* many QEMU's don't support ballooning
|
||||||
|
*/
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(reply);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns: 0 if balloon not supported, +1 if balloon query worked
|
||||||
|
* or -1 on failure
|
||||||
|
*/
|
||||||
|
static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned long newmem) {
|
||||||
|
char *cmd;
|
||||||
|
char *reply = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'newmem' is in KB, QEMU monitor works in MB, and we all wish
|
||||||
|
* we just worked in bytes with unsigned long long everywhere.
|
||||||
|
*/
|
||||||
|
if (virAsprintf(&cmd, "balloon %lu", (newmem / 1024)) < 0) {
|
||||||
|
virReportOOMError(conn);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
|
||||||
|
qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
||||||
|
"%s", _("could not balloon memory allocation"));
|
||||||
|
VIR_FREE(cmd);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
VIR_FREE(cmd);
|
||||||
|
|
||||||
|
/* If the command failed qemu prints: 'unknown command'
|
||||||
|
* No message is printed on success it seems */
|
||||||
|
DEBUG ("balloon reply: %s", reply);
|
||||||
|
if (strstr(reply, "\nunknown command:")) {
|
||||||
|
/* Don't set error - it is expected memory balloon fails on many qemu */
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(reply);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
|
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
|
||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
@ -2427,20 +2520,21 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virDomainIsActive(vm)) {
|
|
||||||
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
||||||
"%s", _("cannot set memory of an active domain"));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newmem > vm->def->maxmem) {
|
if (newmem > vm->def->maxmem) {
|
||||||
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
||||||
"%s", _("cannot set memory higher than max memory"));
|
"%s", _("cannot set memory higher than max memory"));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->def->memory = newmem;
|
if (virDomainIsActive(vm)) {
|
||||||
ret = 0;
|
ret = qemudDomainSetMemoryBalloon(dom->conn, vm, newmem);
|
||||||
|
if (ret == 0)
|
||||||
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
||||||
|
"%s", _("cannot set memory of an active domain"));
|
||||||
|
} else {
|
||||||
|
vm->def->memory = newmem;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (vm)
|
if (vm)
|
||||||
@ -2453,6 +2547,8 @@ static int qemudDomainGetInfo(virDomainPtr dom,
|
|||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
int err;
|
||||||
|
unsigned long balloon;
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
@ -2474,8 +2570,16 @@ static int qemudDomainGetInfo(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = qemudDomainGetMemoryBalloon(dom->conn, vm, &balloon);
|
||||||
|
if (err < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
info->maxMem = vm->def->maxmem;
|
info->maxMem = vm->def->maxmem;
|
||||||
info->memory = vm->def->memory;
|
if (err == 0)
|
||||||
|
/* Balloon not supported, so maxmem is always the allocation */
|
||||||
|
info->memory = vm->def->maxmem;
|
||||||
|
else
|
||||||
|
info->memory = balloon;
|
||||||
info->nrVirtCpu = vm->def->vcpus;
|
info->nrVirtCpu = vm->def->vcpus;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
@ -3170,6 +3274,8 @@ static char *qemudDomainDumpXML(virDomainPtr dom,
|
|||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
|
unsigned long balloon;
|
||||||
|
int err;
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
@ -3181,6 +3287,13 @@ static char *qemudDomainDumpXML(virDomainPtr dom,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Refresh current memory based on balloon info */
|
||||||
|
err = qemudDomainGetMemoryBalloon(dom->conn, vm, &balloon);
|
||||||
|
if (err < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (err > 0)
|
||||||
|
vm->def->memory = balloon;
|
||||||
|
|
||||||
ret = virDomainDefFormat(dom->conn,
|
ret = virDomainDefFormat(dom->conn,
|
||||||
(flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
|
(flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
|
||||||
vm->newDef : vm->def,
|
vm->newDef : vm->def,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user