[libvirt] [PATCH] libvirt:qemu: fix max_balloon less than cur_balloon

In qemuDomainGetXMLDesc, if cur_balloon is bigger than max_balloon, max_balloon should be updated too, otherwise the currentMemory is bigger than memory in dumped xml, which will produce invalid checkpoint by virsh-save. The bug appears like this below: $virsh save vm-num foo.ckp $virsh restore foo.ckp error: XML error: current memory '824320k' exceeds maximum '824288k' Signed-off-by: Zhou Peng <ailvpeng25@gmail.com> --- src/qemu/qemu_driver.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0d3b0bd..96d3219 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4485,7 +4485,13 @@ endjob: if (err < 0) goto cleanup; if (err > 0) + { vm->def->mem.cur_balloon = balloon; + if (balloon > vm->def->mem.max_balloon) + { + vm->def->mem.max_balloon = balloon; + } + } /* err == 0 indicates no balloon support, so ignore it */ } } -- 1.7.7.6

NACK to Zhou's patch (it is only a bandaid trying to cover the symptom, rather than fixing the real bug that happened earlier), but I'm proposing this series in its place. Eric Blake (2): qemu: reflect any memory rounding back to xml conf: allow fuzz in XML with cur balloon > max src/conf/domain_conf.c | 19 +++++++++++++++---- src/qemu/qemu_command.c | 11 +++++++---- src/qemu/qemu_monitor_json.c | 2 +- 3 files changed, 23 insertions(+), 9 deletions(-)

If we round up a user's memory request, we should update the XML to reflect the actual value in use by the VM, rather than giving an artificially small value back to the user. * src/qemu/qemu_command.c (qemuBuildNumaArgStr) (qemuBuildCommandLine): Reflect rounding back to XML. --- src/qemu/qemu_command.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3d2bb6b..8f6471b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3916,8 +3916,9 @@ qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd) virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid); virBufferAddLit(&buf, ",cpus="); qemuBuildNumaCPUArgStr(def->cpu->cells[i].cpumask, &buf); - virBufferAsprintf(&buf, "mem=%d", - VIR_DIV_UP(def->cpu->cells[i].mem, 1024)); + def->cpu->cells[i].mem = VIR_DIV_UP(def->cpu->cells[i].mem, + 1024) * 1024; + virBufferAsprintf(&buf, "mem=%d", def->cpu->cells[i].mem / 1024); if (virBufferError(&buf)) goto error; @@ -4061,10 +4062,12 @@ qemuBuildCommandLine(virConnectPtr conn, /* 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 + * is not supported, then they're out of luck anyway. Update the + * XML to reflect our rounding. */ virCommandAddArg(cmd, "-m"); - virCommandAddArgFormat(cmd, "%llu", VIR_DIV_UP(def->mem.max_balloon, 1024)); + def->mem.max_balloon = VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024; + virCommandAddArgFormat(cmd, "%llu", def->mem.max_balloon / 1024); if (def->mem.hugepage_backed) { if (!driver->hugetlbfs_mount) { qemuReportError(VIR_ERR_INTERNAL_ERROR, -- 1.7.1

On 03/30/2012 11:56 PM, Eric Blake wrote:
If we round up a user's memory request, we should update the XML to reflect the actual value in use by the VM, rather than giving an artificially small value back to the user.
* src/qemu/qemu_command.c (qemuBuildNumaArgStr) (qemuBuildCommandLine): Reflect rounding back to XML. --- src/qemu/qemu_command.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3d2bb6b..8f6471b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3916,8 +3916,9 @@ qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd) virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid); virBufferAddLit(&buf, ",cpus="); qemuBuildNumaCPUArgStr(def->cpu->cells[i].cpumask,&buf); - virBufferAsprintf(&buf, "mem=%d", - VIR_DIV_UP(def->cpu->cells[i].mem, 1024)); + def->cpu->cells[i].mem = VIR_DIV_UP(def->cpu->cells[i].mem, + 1024) * 1024; + virBufferAsprintf(&buf, "mem=%d", def->cpu->cells[i].mem / 1024);
if (virBufferError(&buf)) goto error; @@ -4061,10 +4062,12 @@ qemuBuildCommandLine(virConnectPtr conn,
/* 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 + * is not supported, then they're out of luck anyway. Update the + * XML to reflect our rounding. */ virCommandAddArg(cmd, "-m"); - virCommandAddArgFormat(cmd, "%llu", VIR_DIV_UP(def->mem.max_balloon, 1024)); + def->mem.max_balloon = VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024; + virCommandAddArgFormat(cmd, "%llu", def->mem.max_balloon / 1024); if (def->mem.hugepage_backed) { if (!driver->hugetlbfs_mount) { qemuReportError(VIR_ERR_INTERNAL_ERROR,
It makes sense to reflect the real memory used in qemu command line back to domain conf, but IMHO we need the documentations to declare that the these memory stuffs mighted be rounded up, otherwise I guess bugs will come by confused users. Osier

On 03/31/2012 02:47 PM, Osier Yang wrote:
On 03/30/2012 11:56 PM, Eric Blake wrote:
If we round up a user's memory request, we should update the XML to reflect the actual value in use by the VM, rather than giving an artificially small value back to the user.
* src/qemu/qemu_command.c (qemuBuildNumaArgStr) (qemuBuildCommandLine): Reflect rounding back to XML. --- src/qemu/qemu_command.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3d2bb6b..8f6471b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3916,8 +3916,9 @@ qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd) virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid); virBufferAddLit(&buf, ",cpus="); qemuBuildNumaCPUArgStr(def->cpu->cells[i].cpumask,&buf); - virBufferAsprintf(&buf, "mem=%d", - VIR_DIV_UP(def->cpu->cells[i].mem, 1024)); + def->cpu->cells[i].mem = VIR_DIV_UP(def->cpu->cells[i].mem, + 1024) * 1024; + virBufferAsprintf(&buf, "mem=%d", def->cpu->cells[i].mem / 1024);
if (virBufferError(&buf)) goto error; @@ -4061,10 +4062,12 @@ qemuBuildCommandLine(virConnectPtr conn,
/* 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 + * is not supported, then they're out of luck anyway. Update the + * XML to reflect our rounding. */ virCommandAddArg(cmd, "-m"); - virCommandAddArgFormat(cmd, "%llu", VIR_DIV_UP(def->mem.max_balloon, 1024)); + def->mem.max_balloon = VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024; + virCommandAddArgFormat(cmd, "%llu", def->mem.max_balloon / 1024); if (def->mem.hugepage_backed) { if (!driver->hugetlbfs_mount) { qemuReportError(VIR_ERR_INTERNAL_ERROR,
It makes sense to reflect the real memory used in qemu command line back to domain conf, but IMHO we need the documentations to declare that the these memory stuffs mighted be rounded up, otherwise I guess bugs will come by confused users.
<snip> However, the value will be rounded up to the nearest kibibyte by libvirt, and may be further rounded to the granularity supported by the hypervisor. Some hypervisors also enforce a minimum, such as 4000KiB. unit since 0.9.11 currentMemory </snip> Forgot about it, we already have documentation for it, :=) ACK

Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have current > maximum by the amount of the rounding. Accept this fuzz factor, and silently clamp current down to maximum in that case, rather than failing to reparse XML for an existing VM. * src/conf/domain_conf.c (virDomainDefParseXML): Don't reject existing XML. Based on a report by Zhou Peng. --- src/conf/domain_conf.c | 19 +++++++++++++++---- src/qemu/qemu_monitor_json.c | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4caef6f..7c95920 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7776,10 +7776,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto error; if (def->mem.cur_balloon > def->mem.max_balloon) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("current memory '%lluk' exceeds maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); - goto error; + /* Older libvirt could get into this situation due to + * rounding; if the discrepancy is less than 1MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 1024) > + VIR_DIV_UP(def->mem.max_balloon, 1024)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + goto error; + } else { + VIR_DEBUG("Truncating current %lluk to maximum %lluk", + def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon = def->mem.max_balloon; + } } else if (def->mem.cur_balloon == 0) { def->mem.cur_balloon = def->mem.max_balloon; } diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7093e1d..6d66587 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2022,7 +2022,7 @@ int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon, { int ret; virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon", - "U:value", ((unsigned long long)newmem)*1024, + "U:value", newmem*1024ULL, NULL); virJSONValuePtr reply = NULL; if (!cmd) -- 1.7.1

Thanks for your patch serials. I think they fix the true bug. But I have a little doubt on the fuzz allowance, pls have a see comment in line below. On Fri, Mar 30, 2012 at 11:56 PM, Eric Blake <eblake@redhat.com> wrote:
Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have current > maximum by the amount of the rounding. Accept this fuzz factor, and silently clamp current down to maximum in that case, rather than failing to reparse XML for an existing VM.
* src/conf/domain_conf.c (virDomainDefParseXML): Don't reject existing XML. Based on a report by Zhou Peng. --- src/conf/domain_conf.c | 19 +++++++++++++++---- src/qemu/qemu_monitor_json.c | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4caef6f..7c95920 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7776,10 +7776,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto error;
if (def->mem.cur_balloon > def->mem.max_balloon) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("current memory '%lluk' exceeds maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); - goto error; + /* Older libvirt could get into this situation due to
Do you mean to allow the scene: * The checkpoint( thought invalid by old libvirt) produced by older libvirt can be thought valid if restored by the patched newer libvirt? But it will also allow a typo xml. * Another scene may be live migration between old libvirt and newer libvirt (pls correct me if err) If so, I think these scene should be documented or commented here or in the commit msg explicitly, otherwise this piece of code may confuse many readers, because I don't think cur_balloon can exceed max_balloon again after patched (so if exceed must be typo xml).
+ * rounding; if the discrepancy is less than 1MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 1024) > + VIR_DIV_UP(def->mem.max_balloon, 1024)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + goto error; + } else { + VIR_DEBUG("Truncating current %lluk to maximum %lluk", + def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon = def->mem.max_balloon; + } } else if (def->mem.cur_balloon == 0) { def->mem.cur_balloon = def->mem.max_balloon; } diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7093e1d..6d66587 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2022,7 +2022,7 @@ int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon, { int ret; virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon", - "U:value", ((unsigned long long)newmem)*1024, + "U:value", newmem*1024ULL, NULL); virJSONValuePtr reply = NULL; if (!cmd) -- 1.7.1
-- Zhou Peng

On 03/30/2012 08:36 PM, Zhou Peng wrote:
Thanks for your patch serials. I think they fix the true bug.
But I have a little doubt on the fuzz allowance, pls have a see comment in line below.
if (def->mem.cur_balloon > def->mem.max_balloon) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("current memory '%lluk' exceeds maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); - goto error; + /* Older libvirt could get into this situation due to
Do you mean to allow the scene: * The checkpoint( thought invalid by old libvirt) produced by older libvirt can be thought valid if restored by the patched newer libvirt?
Yes. It is indeed possible to have an older libvirt produce XML where the maximum memory was less than a megabyte boundary, and the current memory is anywhere between that maximum and the actual megabyte boundary.
But it will also allow a typo xml.
Yes, but in practice, it won't make a difference, since it will only allow a typo if the difference falls in the rounding error up to the megabyte boundary.
* Another scene may be live migration between old libvirt and newer libvirt (pls correct me if err)
Yes, that is another situation where old libvirt xml can be output where cur is greater than max, but only by at most the difference due to rounding up to the megabyte boundary.
If so, I think these scene should be documented or commented here or in the commit msg explicitly, otherwise this piece of code may confuse many readers, because I don't think cur_balloon can exceed max_balloon again after patched (so if exceed must be typo xml).
I thought I did document and comment that, but I can add more words since both you and Osier seemed to be confused. v2 coming up. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 03/30/2012 11:56 PM, Eric Blake wrote:
Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have current> maximum by the amount of the rounding. Accept this fuzz factor, and silently clamp current down to maximum in that case, rather than failing to reparse XML for an existing VM.
* src/conf/domain_conf.c (virDomainDefParseXML): Don't reject existing XML. Based on a report by Zhou Peng. --- src/conf/domain_conf.c | 19 +++++++++++++++---- src/qemu/qemu_monitor_json.c | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4caef6f..7c95920 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7776,10 +7776,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto error;
if (def->mem.cur_balloon> def->mem.max_balloon) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("current memory '%lluk' exceeds maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); - goto error; + /* Older libvirt could get into this situation due to + * rounding; if the discrepancy is less than 1MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 1024)> + VIR_DIV_UP(def->mem.max_balloon, 1024)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + goto error; + } else { + VIR_DEBUG("Truncating current %lluk to maximum %lluk", + def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon = def->mem.max_balloon; + }
But this needs the documentation IMHO, it actually changes the behaviours.
} else if (def->mem.cur_balloon == 0) { def->mem.cur_balloon = def->mem.max_balloon; } diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7093e1d..6d66587 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2022,7 +2022,7 @@ int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon, { int ret; virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon", - "U:value", ((unsigned long long)newmem)*1024, + "U:value", newmem*1024ULL, NULL); virJSONValuePtr reply = NULL; if (!cmd)

On 03/31/2012 01:19 AM, Osier Yang wrote:
On 03/30/2012 11:56 PM, Eric Blake wrote:
Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have current> maximum by the amount of the rounding. Accept this fuzz factor, and silently clamp current down to maximum in that case, rather than failing to reparse XML for an existing VM.
* src/conf/domain_conf.c (virDomainDefParseXML): Don't reject existing XML. Based on a report by Zhou Peng. --- src/conf/domain_conf.c | 19 +++++++++++++++---- src/qemu/qemu_monitor_json.c | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-)
- goto error; + /* Older libvirt could get into this situation due to + * rounding; if the discrepancy is less than 1MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 1024)> + VIR_DIV_UP(def->mem.max_balloon, 1024)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + goto error; + } else { + VIR_DEBUG("Truncating current %lluk to maximum %lluk", + def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon = def->mem.max_balloon; + }
But this needs the documentation IMHO, it actually changes the behaviours.
I don't see that this needs to be documented in user documentation, only in the commit message. In 0.9.10, there was no checking done at all. If libvirt output cur > max (possible only up to the fuzz of a megabyte boundary), then this still made no difference: the guest was running with max at the megabyte boundary, so the current fit within the actual max of the guest. If you hand-crafted xml with cur > max and outside the fuzz, you couldn't run anyways, because qemu would complain that cur was out of range. With these two patches, libvirt will now adjust max to the actual megabyte boundary, at which point cur is no longer > max. And when importing an older xml where cur > max, this silently clamps cur down to max, but then libvirt rounds it back up again when passing it to qemu, so you still end up with the same max at the megabyte boundary and cur rounded up to match max. Meanwhile, if the user hand-writes xml with too large of cur, we error out up front rather than letting qemu complain, but it doesn't change the fact that it gets rejected at some point in the chain. That is, I don't see how this fuzz is user visible, so I don't think it needs user visible documentation, only more details in the commit message. v2 with improved commit message coming up. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have dumpxml show cur > max by the amount of the rounding. For example, if a user requested 1048570 KiB memory (just shy of 1GiB), the qemu driver would actually run with 1048576 KiB, and libvirt 0.9.10 would output a current that was 6KiB larger than the maximum. Situations where this could have an impact include, but are not limited to, migration from old to new libvirt, managedsave in old libvirt and start in new libvirt, snapshot creation in old libvirt and revert in new libvirt - without this patch, the new libvirt would reject the VM because of the rounding discrepancy. Fix things by adding a fuzz factor, and silently clamp current down to maximum in that case, rather than failing to reparse XML for an existing VM. From a practical standpoint, this has no user impact: 'virsh dumpxml' will continue to query the running guest rather than rely on the incoming xml, which will see the currect current value, and even if clamping down occurs during parsing, it will be by at most the fuzz factor of a megabyte alignment, and rounded back up when passed back to the hypervisor. Meanwhile, we continue to reject cur > max if the difference is beyond the fuzz factor of nearest megabyte. But this is not a real change in behavior, since with 0.9.10, even though the parser allowed it, later in the processing stream we would reject it at the qemu layer; so rejecting it in the parser just moves error detection to a nicer place. * src/conf/domain_conf.c (virDomainDefParseXML): Don't reject existing XML. Based on a report by Zhou Peng. --- v3: improve the commit message (no change to the code) src/conf/domain_conf.c | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7ea57b9..c800160 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7769,10 +7769,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto error; if (def->mem.cur_balloon > def->mem.max_balloon) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("current memory '%lluk' exceeds maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); - goto error; + /* Older libvirt could get into this situation due to + * rounding; if the discrepancy is less than 1MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 1024) > + VIR_DIV_UP(def->mem.max_balloon, 1024)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + goto error; + } else { + VIR_DEBUG("Truncating current %lluk to maximum %lluk", + def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon = def->mem.max_balloon; + } } else if (def->mem.cur_balloon == 0) { def->mem.cur_balloon = def->mem.max_balloon; } -- 1.7.7.6

Thank you! ACK patch serials On Sat, Mar 31, 2012 at 11:33 PM, Eric Blake <eblake@redhat.com> wrote:
Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have dumpxml show cur > max by the amount of the rounding. For example, if a user requested 1048570 KiB memory (just shy of 1GiB), the qemu driver would actually run with 1048576 KiB, and libvirt 0.9.10 would output a current that was 6KiB larger than the maximum. Situations where this could have an impact include, but are not limited to, migration from old to new libvirt, managedsave in old libvirt and start in new libvirt, snapshot creation in old libvirt and revert in new libvirt - without this patch, the new libvirt would reject the VM because of the rounding discrepancy.
Fix things by adding a fuzz factor, and silently clamp current down to maximum in that case, rather than failing to reparse XML for an existing VM. From a practical standpoint, this has no user impact: 'virsh dumpxml' will continue to query the running guest rather than rely on the incoming xml, which will see the currect current value, and even if clamping down occurs during parsing, it will be by at most the fuzz factor of a megabyte alignment, and rounded back up when passed back to the hypervisor.
Meanwhile, we continue to reject cur > max if the difference is beyond the fuzz factor of nearest megabyte. But this is not a real change in behavior, since with 0.9.10, even though the parser allowed it, later in the processing stream we would reject it at the qemu layer; so rejecting it in the parser just moves error detection to a nicer place.
* src/conf/domain_conf.c (virDomainDefParseXML): Don't reject existing XML. Based on a report by Zhou Peng. ---
v3: improve the commit message (no change to the code)
src/conf/domain_conf.c | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7ea57b9..c800160 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7769,10 +7769,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto error;
if (def->mem.cur_balloon > def->mem.max_balloon) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("current memory '%lluk' exceeds maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); - goto error; + /* Older libvirt could get into this situation due to + * rounding; if the discrepancy is less than 1MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 1024) > + VIR_DIV_UP(def->mem.max_balloon, 1024)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + goto error; + } else { + VIR_DEBUG("Truncating current %lluk to maximum %lluk", + def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon = def->mem.max_balloon; + } } else if (def->mem.cur_balloon == 0) { def->mem.cur_balloon = def->mem.max_balloon; } -- 1.7.7.6
-- Zhou Peng

On 03/31/2012 10:22 AM, Zhou Peng wrote:
Thank you! ACK patch serials
On Sat, Mar 31, 2012 at 11:33 PM, Eric Blake <eblake@redhat.com> wrote:
Commit 1b1402b introduced a regression. Since older libvirt versions would silently round memory up (until the previous patch), but populated current memory based on querying the guest, it was possible to have dumpxml show cur > max by the amount of the rounding. For example, if a user requested 1048570 KiB memory (just shy of 1GiB), the qemu driver would actually run with 1048576 KiB, and libvirt 0.9.10 would output a current that was 6KiB larger than the maximum. Situations where this could have an impact include, but are not limited to, migration from old to new libvirt, managedsave in old libvirt and start in new libvirt, snapshot creation in old libvirt and revert in new libvirt - without this patch, the new libvirt would reject the VM because of the rounding discrepancy.
I've gone ahead and pushed this, since it will avoid regressions when 0.9.11 is released. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Eric Blake
-
Osier Yang
-
Zhou Peng