[Libvir] [PATCH] Implement memory operations for qemu driver

The attached patch implements the following operations for the qemu driver: virDomainGetMaxMemory virDomainSetMaxMemory virDomainSetMemory A few questions/comments: 1) I changed maxmem and memory in the qemu_vm_def struct to unsigned long to match the public api for memory values. Seems to work, but not sure if there are any undesirable side effects to this. 2) Should SetMaxMem be able to be called on a running guest? This code allows it, since maxmem is basically a metavalue that doesn't directly affect a guest. 3) Should maxmem be able to be set lower than the currently allocated mem? This code does not allow this. If this changed, would also need to take into account how we would handle this if we can change the maxmem while the guest is running. After rethinking, we probably should be able to do this, but I haven't changed the code. Thanks, Cole diff --git a/src/qemu_conf.c b/src/qemu_conf.c index a196bb8..f6ae06b 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -1650,7 +1650,7 @@ int qemudBuildCommandLine(virConnectPtr conn, (vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */ (vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */ - snprintf(memory, sizeof(memory), "%d", vm->def->memory/1024); + snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024); snprintf(vcpus, sizeof(vcpus), "%d", vm->def->vcpus); if (!(*argv = malloc(sizeof(**argv) * (len+1)))) @@ -2820,9 +2820,9 @@ char *qemudGenerateXML(virConnectPtr conn, virUUIDFormat(uuid, uuidstr); if (virBufferVSprintf(buf, " <uuid>%s</uuid>\n", uuidstr) < 0) goto no_memory; - if (virBufferVSprintf(buf, " <memory>%d</memory>\n", def->maxmem) < 0) + if (virBufferVSprintf(buf, " <memory>%lu</memory>\n", def->maxmem) < 0) goto no_memory; - if (virBufferVSprintf(buf, " <currentMemory>%d</currentMemory>\n", def->memory) < 0) + if (virBufferVSprintf(buf, " <currentMemory>%lu</currentMemory>\n", def->memory) < 0) goto no_memory; if (virBufferVSprintf(buf, " <vcpu>%d</vcpu>\n", def->vcpus) < 0) goto no_memory; diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 12aa6ae..c1aae75 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -193,8 +193,8 @@ struct qemud_vm_def { unsigned char uuid[VIR_UUID_BUFLEN]; char name[QEMUD_MAX_NAME_LEN]; - int memory; - int maxmem; + unsigned long memory; + unsigned long maxmem; int vcpus; int noReboot; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 2b4c2a6..215f4c4 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1765,6 +1765,66 @@ static char *qemudDomainGetOSType(virDomainPtr dom) { return type; } +/* Returns max memory in kb, 0 if error */ +static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "no domain with matching uuid '%s'", dom->uuid); + return 0; + } + + return vm->def->maxmem; +} + +static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "no domain with matching uuid '%s'", dom->uuid); + return -1; + } + + if (memory < vm->def->maxmem) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + "cannot set max memory lower than current memory"); + return -1; + } + + vm->def->maxmem = memory; + return 0; +} + +static int qemudDomainSetMemory(virDomainPtr dom, unsigned long memory) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "no domain with matching uuid '%s'", dom->uuid); + return -1; + } + + if (qemudIsActiveVM(vm)) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + "cannot set memory of an active domain"); + return -1; + } + + if (memory > vm->def->maxmem) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + "cannot set memory higher than max memory"); + return -1; + } + + vm->def->memory = memory; + return 0; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; @@ -2886,9 +2946,9 @@ static virDriver qemuDriver = { NULL, /* domainReboot */ qemudDomainDestroy, /* domainDestroy */ qemudDomainGetOSType, /* domainGetOSType */ - NULL, /* domainGetMaxMemory */ - NULL, /* domainSetMaxMemory */ - NULL, /* domainSetMemory */ + qemudDomainGetMaxMemory, /* domainGetMaxMemory */ + qemudDomainSetMaxMemory, /* domainSetMaxMemory */ + qemudDomainSetMemory, /* domainSetMemory */ qemudDomainGetInfo, /* domainGetInfo */ qemudDomainSave, /* domainSave */ qemudDomainRestore, /* domainRestore */

On Mon, Mar 17, 2008 at 04:21:04PM -0400, Cole Robinson wrote:
The attached patch implements the following operations for the qemu driver:
virDomainGetMaxMemory virDomainSetMaxMemory virDomainSetMemory
The patch itself, +1. Maybe we should investigate whether qemu/kvm does or will support a way to dynamically set the memory of an active domain. (There is no current support for this that I can see from the documentation).
A few questions/comments:
1) I changed maxmem and memory in the qemu_vm_def struct to unsigned long to match the public api for memory values. Seems to work, but not sure if there are any undesirable side effects to this.
It seems better as unsigned long, particularly for supporting 64 bit archs with lots of memory.
2) Should SetMaxMem be able to be called on a running guest? This code allows it, since maxmem is basically a metavalue that doesn't directly affect a guest.
3) Should maxmem be able to be set lower than the currently allocated mem? This code does not allow this. If this changed, would also need to take into account how we would handle this if we can change the maxmem while the guest is running. After rethinking, we probably should be able to do this, but I haven't changed the code.
As far as I understand what maxmem means (for Xen), this seems to be correct behaviour. Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top

Richard W.M. Jones wrote:
2) Should SetMaxMem be able to be called on a running guest? This code allows it, since maxmem is basically a metavalue that doesn't directly affect a guest.
3) Should maxmem be able to be set lower than the currently allocated mem? This code does not allow this. If this changed, would also need to take into account how we would handle this if we can change the maxmem while the guest is running. After rethinking, we probably should be able to do this, but I haven't changed the code.
As far as I understand what maxmem means (for Xen), this seems to be correct behaviour.
Rich.
I just checked this: xm seems to explicitly reject setting maxmem lower than current mem for a guest in any state, but going through virsh you can set maxmem to any value on an inactive guest. But it is probably better to just stick with the xm convention. - Cole

On Tue, Mar 18, 2008 at 10:04:12AM -0400, Cole Robinson wrote:
Richard W.M. Jones wrote:
2) Should SetMaxMem be able to be called on a running guest? This code allows it, since maxmem is basically a metavalue that doesn't directly affect a guest.
3) Should maxmem be able to be set lower than the currently allocated mem? This code does not allow this. If this changed, would also need to take into account how we would handle this if we can change the maxmem while the guest is running. After rethinking, we probably should be able to do this, but I haven't changed the code.
As far as I understand what maxmem means (for Xen), this seems to be correct behaviour.
Rich.
I just checked this: xm seems to explicitly reject setting maxmem lower than current mem for a guest in any state, but going through virsh you can set maxmem to any value on an inactive guest. But it is probably better to just stick with the xm convention.
in practice it should be fine to change max_mem on any domain which has no running instance, as long as the domain will go though a create to run again, because that's at create time that some of the data is allocated based on that maximum size. For example resizing and restoring a domain which was previously saved to disk won't work in practice, and it's impossible for libvirt or the hypervisor to know if a domain will be restarted with Create() or Restore(). I think xm is being a bit too cautious there, though I can understand their decision. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

Cole Robinson <crobinso@redhat.com> wrote:
The attached patch implements the following operations for the qemu driver: ... + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "no domain with matching uuid '%s'", dom->uuid); ... + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + "cannot set max memory lower than current memory"); ...
Hi Cole. The patch looks good. Please put _(...) around diagnostics, so that they end up being translated.

Jim Meyering wrote:
Cole Robinson <crobinso@redhat.com> wrote:
The attached patch implements the following operations for the qemu driver: ... + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "no domain with matching uuid '%s'", dom->uuid); ... + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + "cannot set max memory lower than current memory"); ...
Hi Cole. The patch looks good. Please put _(...) around diagnostics, so that they end up being translated.
Fixed patch attached. Thanks, Cole diff --git a/src/qemu_conf.c b/src/qemu_conf.c index a196bb8..f6ae06b 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -1650,7 +1650,7 @@ int qemudBuildCommandLine(virConnectPtr conn, (vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */ (vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */ - snprintf(memory, sizeof(memory), "%d", vm->def->memory/1024); + snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024); snprintf(vcpus, sizeof(vcpus), "%d", vm->def->vcpus); if (!(*argv = malloc(sizeof(**argv) * (len+1)))) @@ -2820,9 +2820,9 @@ char *qemudGenerateXML(virConnectPtr conn, virUUIDFormat(uuid, uuidstr); if (virBufferVSprintf(buf, " <uuid>%s</uuid>\n", uuidstr) < 0) goto no_memory; - if (virBufferVSprintf(buf, " <memory>%d</memory>\n", def->maxmem) < 0) + if (virBufferVSprintf(buf, " <memory>%lu</memory>\n", def->maxmem) < 0) goto no_memory; - if (virBufferVSprintf(buf, " <currentMemory>%d</currentMemory>\n", def->memory) < 0) + if (virBufferVSprintf(buf, " <currentMemory>%lu</currentMemory>\n", def->memory) < 0) goto no_memory; if (virBufferVSprintf(buf, " <vcpu>%d</vcpu>\n", def->vcpus) < 0) goto no_memory; diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 12aa6ae..c1aae75 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -193,8 +193,8 @@ struct qemud_vm_def { unsigned char uuid[VIR_UUID_BUFLEN]; char name[QEMUD_MAX_NAME_LEN]; - int memory; - int maxmem; + unsigned long memory; + unsigned long maxmem; int vcpus; int noReboot; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 2b4c2a6..6aaf23e 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1765,6 +1765,66 @@ static char *qemudDomainGetOSType(virDomainPtr dom) { return type; } +/* Returns max memory in kb, 0 if error */ +static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid '%s'"), dom->uuid); + return 0; + } + + return vm->def->maxmem; +} + +static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid '%s'"), dom->uuid); + return -1; + } + + if (memory < vm->def->maxmem) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("cannot set max memory lower than current memory")); + return -1; + } + + vm->def->maxmem = memory; + return 0; +} + +static int qemudDomainSetMemory(virDomainPtr dom, unsigned long memory) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid '%s'"), dom->uuid); + return -1; + } + + if (qemudIsActiveVM(vm)) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot set memory of an active domain")); + return -1; + } + + if (memory > vm->def->maxmem) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("cannot set memory higher than max memory")); + return -1; + } + + vm->def->memory = memory; + return 0; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; @@ -2886,9 +2946,9 @@ static virDriver qemuDriver = { NULL, /* domainReboot */ qemudDomainDestroy, /* domainDestroy */ qemudDomainGetOSType, /* domainGetOSType */ - NULL, /* domainGetMaxMemory */ - NULL, /* domainSetMaxMemory */ - NULL, /* domainSetMemory */ + qemudDomainGetMaxMemory, /* domainGetMaxMemory */ + qemudDomainSetMaxMemory, /* domainSetMaxMemory */ + qemudDomainSetMemory, /* domainSetMemory */ qemudDomainGetInfo, /* domainGetInfo */ qemudDomainSave, /* domainSave */ qemudDomainRestore, /* domainRestore */

On Tue, Mar 18, 2008 at 10:05:48AM -0400, Cole Robinson wrote:
Jim Meyering wrote:
Cole Robinson <crobinso@redhat.com> wrote:
The attached patch implements the following operations for the qemu driver: ... + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "no domain with matching uuid '%s'", dom->uuid); ... + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + "cannot set max memory lower than current memory"); ...
Hi Cole. The patch looks good. Please put _(...) around diagnostics, so that they end up being translated.
Fixed patch attached.
Looks fine, +1 Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

Cole Robinson wrote:
The attached patch implements the following operations for the qemu driver:
virDomainGetMaxMemory virDomainSetMaxMemory virDomainSetMemory
A few questions/comments:
1) I changed maxmem and memory in the qemu_vm_def struct to unsigned long to match the public api for memory values. Seems to work, but not sure if there are any undesirable side effects to this.
2) Should SetMaxMem be able to be called on a running guest? This code allows it, since maxmem is basically a metavalue that doesn't directly affect a guest.
3) Should maxmem be able to be set lower than the currently allocated mem? This code does not allow this. If this changed, would also need to take into account how we would handle this if we can change the maxmem while the guest is running. After rethinking, we probably should be able to do this, but I haven't changed the code.
Thanks, Cole
In testing this with virt-manager I found a bug: I was using comparing maxmem against the wrong memory value. Fixed this and updated the parameter names to be a bit more clear. Seems to work as excepted now. Thanks, Cole diff --git a/src/qemu_conf.c b/src/qemu_conf.c index a196bb8..f6ae06b 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -1650,7 +1650,7 @@ int qemudBuildCommandLine(virConnectPtr conn, (vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */ (vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */ - snprintf(memory, sizeof(memory), "%d", vm->def->memory/1024); + snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024); snprintf(vcpus, sizeof(vcpus), "%d", vm->def->vcpus); if (!(*argv = malloc(sizeof(**argv) * (len+1)))) @@ -2820,9 +2820,9 @@ char *qemudGenerateXML(virConnectPtr conn, virUUIDFormat(uuid, uuidstr); if (virBufferVSprintf(buf, " <uuid>%s</uuid>\n", uuidstr) < 0) goto no_memory; - if (virBufferVSprintf(buf, " <memory>%d</memory>\n", def->maxmem) < 0) + if (virBufferVSprintf(buf, " <memory>%lu</memory>\n", def->maxmem) < 0) goto no_memory; - if (virBufferVSprintf(buf, " <currentMemory>%d</currentMemory>\n", def->memory) < 0) + if (virBufferVSprintf(buf, " <currentMemory>%lu</currentMemory>\n", def->memory) < 0) goto no_memory; if (virBufferVSprintf(buf, " <vcpu>%d</vcpu>\n", def->vcpus) < 0) goto no_memory; diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 12aa6ae..c1aae75 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -193,8 +193,8 @@ struct qemud_vm_def { unsigned char uuid[VIR_UUID_BUFLEN]; char name[QEMUD_MAX_NAME_LEN]; - int memory; - int maxmem; + unsigned long memory; + unsigned long maxmem; int vcpus; int noReboot; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 2b4c2a6..af5fc40 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1765,6 +1765,66 @@ static char *qemudDomainGetOSType(virDomainPtr dom) { return type; } +/* Returns max memory in kb, 0 if error */ +static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid '%s'"), dom->uuid); + return 0; + } + + return vm->def->maxmem; +} + +static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid '%s'"), dom->uuid); + return -1; + } + + if (newmax < vm->def->memory) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("cannot set max memory lower than current memory")); + return -1; + } + + vm->def->maxmem = newmax; + return 0; +} + +static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid); + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid '%s'"), dom->uuid); + return -1; + } + + if (qemudIsActiveVM(vm)) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot set memory of an active domain")); + return -1; + } + + if (newmem > vm->def->maxmem) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("cannot set memory higher than max memory")); + return -1; + } + + vm->def->memory = newmem; + return 0; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; @@ -2886,9 +2946,9 @@ static virDriver qemuDriver = { NULL, /* domainReboot */ qemudDomainDestroy, /* domainDestroy */ qemudDomainGetOSType, /* domainGetOSType */ - NULL, /* domainGetMaxMemory */ - NULL, /* domainSetMaxMemory */ - NULL, /* domainSetMemory */ + qemudDomainGetMaxMemory, /* domainGetMaxMemory */ + qemudDomainSetMaxMemory, /* domainSetMaxMemory */ + qemudDomainSetMemory, /* domainSetMemory */ qemudDomainGetInfo, /* domainGetInfo */ qemudDomainSave, /* domainSave */ qemudDomainRestore, /* domainRestore */

On Tue, Mar 18, 2008 at 02:28:36PM -0400, Cole Robinson wrote:
Cole Robinson wrote:
The attached patch implements the following operations for the qemu driver:
virDomainGetMaxMemory virDomainSetMaxMemory virDomainSetMemory
A few questions/comments:
1) I changed maxmem and memory in the qemu_vm_def struct to unsigned long to match the public api for memory values. Seems to work, but not sure if there are any undesirable side effects to this.
2) Should SetMaxMem be able to be called on a running guest? This code allows it, since maxmem is basically a metavalue that doesn't directly affect a guest.
3) Should maxmem be able to be set lower than the currently allocated mem? This code does not allow this. If this changed, would also need to take into account how we would handle this if we can change the maxmem while the guest is running. After rethinking, we probably should be able to do this, but I haven't changed the code.
Thanks, Cole
In testing this with virt-manager I found a bug: I was using comparing maxmem against the wrong memory value. Fixed this and updated the parameter names to be a bit more clear. Seems to work as excepted now.
Okidoc, commited, thanks ! Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
participants (4)
-
Cole Robinson
-
Daniel Veillard
-
Jim Meyering
-
Richard W.M. Jones