[libvirt] [PATCH 0/7] Automaticaly fill <memory> element for NUMA enabled guests

Conclusion of the memory refactoring series. These patches depend on the two previous series and for convenience can be fetched at: git fetch git://pipo.sk/pipo/libvirt.git/ memory-refactors This series changes the behavior of the <memory> element in case the guest has NUMA enabled and fills automatically the sum of sizes of numa nodes instead of relying on the user passing correct data. Peter Krempa (7): qemu: Forbid seting maximum memory size with the API with NUMA enabled qemu: lxc: Clarify error message when setting current memory conf: Hoist validation of memory size into the post parse callback conf: Replace access to def-mem.max_balloon with accessor functions qemu: command: Add helper to align memory sizes conf: numa: Add helper to count total memory size configured in NUMA conf: Automatically use NUMA memory size in case NUMA is enabled src/conf/domain_conf.c | 101 ++++++++++++++++----- src/conf/domain_conf.h | 4 + src/conf/numa_conf.c | 13 +++ src/conf/numa_conf.h | 1 + src/hyperv/hyperv_driver.c | 2 +- src/libvirt_private.syms | 4 + src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 8 +- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_driver.c | 27 +++--- src/lxc/lxc_fuse.c | 4 +- src/lxc/lxc_native.c | 4 +- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_sdk.c | 12 +-- src/phyp/phyp_driver.c | 11 ++- src/qemu/qemu_command.c | 23 +++-- src/qemu/qemu_domain.c | 21 +++++ src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 44 +++++---- src/qemu/qemu_hotplug.c | 8 +- src/qemu/qemu_process.c | 2 +- src/test/test_driver.c | 8 +- src/uml/uml_driver.c | 8 +- src/vbox/vbox_common.c | 4 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 12 +-- src/xen/xm_internal.c | 14 +-- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 4 +- src/xenconfig/xen_common.c | 8 +- src/xenconfig/xen_sxpr.c | 9 +- .../qemuxml2argv-numatune-memnode.args | 2 +- 33 files changed, 248 insertions(+), 124 deletions(-) -- 2.2.2

NUMA enabled guest configuration explicitly specifies memory sizes for individual nodes. Allowing the virDomainSetMemoryFlags API (and friends) to change the total doesn't make sense as the individual node configs are not updated in that case. Forbid use of the API in case NUMA is specified. --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2b0dac7..e2abbe0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2307,6 +2307,16 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, if (flags & VIR_DOMAIN_AFFECT_CONFIG) { /* Help clang 2.8 decipher the logic flow. */ sa_assert(persistentDef); + + /* resizing memory with NUMA nodes specified doesn't work as there + * is no way to decrease the individual node sizes along */ + if (virDomainNumaGetNodeCount(persistentDef->numa) > 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("maximum memory size of a domain with NUMA " + "nodes cannot be modified with this API")); + goto endjob; + } + persistentDef->mem.max_balloon = newmem; if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; -- 2.2.2

$sub s/seting/setting On 02/18/2015 09:16 AM, Peter Krempa wrote:
NUMA enabled guest configuration explicitly specifies memory sizes for individual nodes. Allowing the virDomainSetMemoryFlags API (and friends) to change the total doesn't make sense as the individual node configs are not updated in that case.
Forbid use of the API in case NUMA is specified. --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
Peeking forward to the next patch it seems src/lxc/lxc_driver.c has the same flags & VIR_DOMAIN_MEM_MAXIMUM, then flags & VIR_DOMAIN_AFFECT_CONFIG. So if the theory is lxc copied qemu, then should this also be done for lxc? Especially since you're altering the else portion for both.
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2b0dac7..e2abbe0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2307,6 +2307,16 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, if (flags & VIR_DOMAIN_AFFECT_CONFIG) { /* Help clang 2.8 decipher the logic flow. */ sa_assert(persistentDef); + + /* resizing memory with NUMA nodes specified doesn't work as there + * is no way to decrease the individual node sizes along */
Looks like you didn't finish your thoughts with the comment... 'along ?' Seems reasonable, but is there a downside? I don't have the relationship between the balloon driver and numa currently paged in ;-) It also seems that something like this would be documented - that is - in the API and perhaps virsh.pod that changing maxmem for certain hypervisors for domains using numa cannot be done (instead use...). John
+ if (virDomainNumaGetNodeCount(persistentDef->numa) > 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("maximum memory size of a domain with NUMA " + "nodes cannot be modified with this API")); + goto endjob; + } + persistentDef->mem.max_balloon = newmem; if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem;

On Fri, Feb 20, 2015 at 07:37:03 -0500, John Ferlan wrote:
$sub
s/seting/setting
On 02/18/2015 09:16 AM, Peter Krempa wrote:
NUMA enabled guest configuration explicitly specifies memory sizes for individual nodes. Allowing the virDomainSetMemoryFlags API (and friends) to change the total doesn't make sense as the individual node configs are not updated in that case.
Forbid use of the API in case NUMA is specified. --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
Peeking forward to the next patch it seems src/lxc/lxc_driver.c has the same flags & VIR_DOMAIN_MEM_MAXIMUM, then flags & VIR_DOMAIN_AFFECT_CONFIG.
So if the theory is lxc copied qemu, then should this also be done for lxc? Especially since you're altering the else portion for both.
I don't think that LXC supports NUMA to the extent of NUMA cells or specific NUMA configuration so I don't think it makes sense to patch there.
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2b0dac7..e2abbe0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2307,6 +2307,16 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, if (flags & VIR_DOMAIN_AFFECT_CONFIG) { /* Help clang 2.8 decipher the logic flow. */ sa_assert(persistentDef); + + /* resizing memory with NUMA nodes specified doesn't work as there + * is no way to decrease the individual node sizes along */
Looks like you didn't finish your thoughts with the comment... 'along ?'
Looks like I've got sidetracked while writing that message. Since I'll be reposting that patch I'll try to fix it.
Seems reasonable, but is there a downside? I don't have the relationship between the balloon driver and numa currently paged in ;-)
It also seems that something like this would be documented - that is - in the API and perhaps virsh.pod that changing maxmem for certain hypervisors for domains using numa cannot be done (instead use...).
Hmm yeah, we should add docs for this one.
John
Peter

Commit 60f7303c151cccdbe214b9f9ac59ecaf95cbf24b introduced the error message but it's unclear whether the persistent config or the live config tripped the message. Later the LXC driver copied the same code. Separate the message which will also clarify the code. --- src/lxc/lxc_driver.c | 21 +++++++++++---------- src/qemu/qemu_driver.c | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 3adb21d..5af0554 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -742,18 +742,19 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, goto cleanup; } } else { - unsigned long oldmax = 0; - - if (flags & VIR_DOMAIN_AFFECT_LIVE) - oldmax = vm->def->mem.max_balloon; - if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - if (!oldmax || oldmax > persistentDef->mem.max_balloon) - oldmax = persistentDef->mem.max_balloon; + if (flags & VIR_DOMAIN_AFFECT_LIVE && + newmem > vm->def->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the live instance can't be less " + "than the current memory")); + goto cleanup; } - if (newmem > oldmax) { - virReportError(VIR_ERR_INVALID_ARG, - "%s", _("Cannot set memory higher than max memory")); + if (flags & VIR_DOMAIN_AFFECT_CONFIG && + newmem > persistentDef->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the persistent configuration can't " + "be less than the current memory")); goto cleanup; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e2abbe0..4458e02 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2326,18 +2326,19 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } else { /* resize the current memory */ - unsigned long oldmax = 0; - - if (flags & VIR_DOMAIN_AFFECT_LIVE) - oldmax = vm->def->mem.max_balloon; - if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - if (!oldmax || oldmax > persistentDef->mem.max_balloon) - oldmax = persistentDef->mem.max_balloon; + if (flags & VIR_DOMAIN_AFFECT_LIVE && + newmem > vm->def->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the live instance can't be less " + "than the current memory")); + goto endjob; } - if (newmem > oldmax) { + if (flags & VIR_DOMAIN_AFFECT_CONFIG && + newmem > persistentDef->mem.max_balloon) { virReportError(VIR_ERR_INVALID_ARG, "%s", - _("cannot set memory higher than max memory")); + _("max memory of the persistent configuration can't " + "be less than the current memory")); goto endjob; } -- 2.2.2

On 02/18/2015 09:16 AM, Peter Krempa wrote:
Commit 60f7303c151cccdbe214b9f9ac59ecaf95cbf24b introduced the error message but it's unclear whether the persistent config or the live config tripped the message. Later the LXC driver copied the same code.
Separate the message which will also clarify the code. --- src/lxc/lxc_driver.c | 21 +++++++++++---------- src/qemu/qemu_driver.c | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 3adb21d..5af0554 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -742,18 +742,19 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, goto cleanup; } } else { - unsigned long oldmax = 0; - - if (flags & VIR_DOMAIN_AFFECT_LIVE) - oldmax = vm->def->mem.max_balloon; - if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - if (!oldmax || oldmax > persistentDef->mem.max_balloon) - oldmax = persistentDef->mem.max_balloon; + if (flags & VIR_DOMAIN_AFFECT_LIVE && + newmem > vm->def->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the live instance can't be less " + "than the current memory")); + goto cleanup; }
- if (newmem > oldmax) { - virReportError(VIR_ERR_INVALID_ARG, - "%s", _("Cannot set memory higher than max memory")); + if (flags & VIR_DOMAIN_AFFECT_CONFIG && + newmem > persistentDef->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the persistent configuration can't " + "be less than the current memory"));
This reads awkwardly... This is the non maxmem path - that is we're just setting memory and the comparison is that if the new memory value is greater than the defined maximum, then there is an error. Could be done in one (somewhat ugly) statement too... if ((flags & VIR_DOMAIN_AFFECT_LIVE && newmem > vm->def->mem.max_balloon) || (flags & VIR_DOMAIN_AFFECT_CONFIG && newmem > persistentDef->mem.max_balloon)) { unsigned long maxmem = flags & VIR_DOMAIN_AFFECT_LIVE ? vm->def->mem.max_balloon : persistentDef->mem.max_balloon; virReportError(VIR_ERR_INVALID_ARG, _("new memory value '%lu' cannot be greater " "than the maximum value '%lu' for the %s"), newmem, maxmem, flags & VIR_DOMAIN_AFFECT_LIVE ? _("live instance") : _("persistent configuration")); ACK on the idea and I'm sure you'll be able to do the message properly. I did try to do a "cond ? arg2, arg3 : arg2, arg3" instead of setting maxmem, but wasn't successful in a quick attempt... John
goto cleanup; }
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e2abbe0..4458e02 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2326,18 +2326,19 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
} else { /* resize the current memory */ - unsigned long oldmax = 0; - - if (flags & VIR_DOMAIN_AFFECT_LIVE) - oldmax = vm->def->mem.max_balloon; - if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - if (!oldmax || oldmax > persistentDef->mem.max_balloon) - oldmax = persistentDef->mem.max_balloon; + if (flags & VIR_DOMAIN_AFFECT_LIVE && + newmem > vm->def->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the live instance can't be less " + "than the current memory")); + goto endjob; }
- if (newmem > oldmax) { + if (flags & VIR_DOMAIN_AFFECT_CONFIG && + newmem > persistentDef->mem.max_balloon) { virReportError(VIR_ERR_INVALID_ARG, "%s", - _("cannot set memory higher than max memory")); + _("max memory of the persistent configuration can't " + "be less than the current memory")); goto endjob; }

On Fri, Feb 20, 2015 at 08:16:17 -0500, John Ferlan wrote:
On 02/18/2015 09:16 AM, Peter Krempa wrote:
Commit 60f7303c151cccdbe214b9f9ac59ecaf95cbf24b introduced the error message but it's unclear whether the persistent config or the live config tripped the message. Later the LXC driver copied the same code.
Separate the message which will also clarify the code. --- src/lxc/lxc_driver.c | 21 +++++++++++---------- src/qemu/qemu_driver.c | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 3adb21d..5af0554 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -742,18 +742,19 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, goto cleanup; } } else { - unsigned long oldmax = 0; - - if (flags & VIR_DOMAIN_AFFECT_LIVE) - oldmax = vm->def->mem.max_balloon; - if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - if (!oldmax || oldmax > persistentDef->mem.max_balloon) - oldmax = persistentDef->mem.max_balloon; + if (flags & VIR_DOMAIN_AFFECT_LIVE && + newmem > vm->def->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the live instance can't be less " + "than the current memory")); + goto cleanup; }
- if (newmem > oldmax) { - virReportError(VIR_ERR_INVALID_ARG, - "%s", _("Cannot set memory higher than max memory")); + if (flags & VIR_DOMAIN_AFFECT_CONFIG && + newmem > persistentDef->mem.max_balloon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("max memory of the persistent configuration can't " + "be less than the current memory"));
This reads awkwardly... This is the non maxmem path - that is we're just setting memory and the comparison is that if the new memory value is greater than the defined maximum, then there is an error.
Could be done in one (somewhat ugly) statement too...
I specifically wanted to avoid one statement ...
if ((flags & VIR_DOMAIN_AFFECT_LIVE && newmem > vm->def->mem.max_balloon) || (flags & VIR_DOMAIN_AFFECT_CONFIG && newmem > persistentDef->mem.max_balloon)) { unsigned long maxmem = flags & VIR_DOMAIN_AFFECT_LIVE ? vm->def->mem.max_balloon : persistentDef->mem.max_balloon;a
... as you need an intermediate variable ...
virReportError(VIR_ERR_INVALID_ARG, _("new memory value '%lu' cannot be greater " "than the maximum value '%lu' for the %s"), newmem, maxmem, flags & VIR_DOMAIN_AFFECT_LIVE ?
... ternary operators ...
_("live instance") : _("persistent configuration"));
... and hard to translate strings.
ACK on the idea and I'm sure you'll be able to do the message properly. I did try to do a "cond ? arg2, arg3 : arg2, arg3" instead of setting maxmem, but wasn't successful in a quick attempt...
I'll try to improve the error message but I will not change the two-condition approach. Peter

Later patches will need to access the full definition to do check the memory size and thus the checking needs to be done after the whole definition including devices is known. --- src/conf/domain_conf.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 15d4fe0..6ef499d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3172,6 +3172,26 @@ virDomainDefPostParseInternal(virDomainDefPtr def, return -1; } + if (def->mem.cur_balloon > def->mem.max_balloon) { + /* Older libvirt could get into this situation due to + * rounding; if the discrepancy is less than 4MiB, we silently + * round down, otherwise we flag the issue. */ + if (VIR_DIV_UP(def->mem.cur_balloon, 4096) > + VIR_DIV_UP(def->mem.max_balloon, 4096)) { + virReportError(VIR_ERR_XML_ERROR, + _("current memory '%lluk' exceeds " + "maximum '%lluk'"), + def->mem.cur_balloon, def->mem.max_balloon); + return -1; + } 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; + } + /* * Some really crazy backcompat stuff for consoles * @@ -13036,27 +13056,6 @@ virDomainDefParseXML(xmlDocPtr xml, } VIR_FREE(tmp); - if (def->mem.cur_balloon > def->mem.max_balloon) { - /* Older libvirt could get into this situation due to - * rounding; if the discrepancy is less than 4MiB, we silently - * round down, otherwise we flag the issue. */ - if (VIR_DIV_UP(def->mem.cur_balloon, 4096) > - VIR_DIV_UP(def->mem.max_balloon, 4096)) { - virReportError(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; - } - - if ((n = virXPathNodeSet("./memoryBacking/hugepages/page", ctxt, &nodes)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot extract hugepages nodes")); -- 2.2.2

On 02/18/2015 09:16 AM, Peter Krempa wrote:
Later patches will need to access the full definition to do check the memory size and thus the checking needs to be done after the whole definition including devices is known. --- src/conf/domain_conf.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-)
ACK - seems reasonable... John

On Fri, Feb 20, 2015 at 08:19:26 -0500, John Ferlan wrote:
On 02/18/2015 09:16 AM, Peter Krempa wrote:
Later patches will need to access the full definition to do check the memory size and thus the checking needs to be done after the whole definition including devices is known. --- src/conf/domain_conf.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-)
ACK - seems reasonable...
This one is now pushed. Thanks. Peter

As there are two possible approaches to define a domain's memory size - one used with legacy, non-NUMA VMs configured in the <memory> element and per-node based approach on NUMA machines - the user needs to make sure that both are specified correctly in the NUMA case. To avoid this burden on the user I'd like to replace the NUMA case with automatic totaling of the memory size. To achieve this I need to replace direct access to the virDomainMemtune's 'max_balloon' field with two separate getters depending on the desired size. The two sizes are needed as: 1) Startup memory size doesn't include memory modules in some hypervisors. 2) After startup these count as the usable memory size. Note that the comments for the functions are future aware and document state that will be present after a few later patches. --- src/conf/domain_conf.c | 66 ++++++++++++++++++++++++++++++++++------ src/conf/domain_conf.h | 4 +++ src/hyperv/hyperv_driver.c | 2 +- src/libvirt_private.syms | 3 ++ src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 8 ++--- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_driver.c | 10 +++--- src/lxc/lxc_fuse.c | 4 +-- src/lxc/lxc_native.c | 4 +-- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_sdk.c | 12 ++++---- src/phyp/phyp_driver.c | 11 ++++--- src/qemu/qemu_command.c | 18 +++++++---- src/qemu/qemu_driver.c | 19 ++++++------ src/qemu/qemu_hotplug.c | 8 +++-- src/qemu/qemu_process.c | 2 +- src/test/test_driver.c | 8 ++--- src/uml/uml_driver.c | 8 ++--- src/vbox/vbox_common.c | 4 +-- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 12 ++++---- src/xen/xm_internal.c | 14 ++++----- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 4 +-- src/xenconfig/xen_common.c | 8 +++-- src/xenconfig/xen_sxpr.c | 9 +++--- 28 files changed, 160 insertions(+), 90 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6ef499d..e95851a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3172,24 +3172,26 @@ virDomainDefPostParseInternal(virDomainDefPtr def, return -1; } - if (def->mem.cur_balloon > def->mem.max_balloon) { + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) { /* Older libvirt could get into this situation due to * rounding; if the discrepancy is less than 4MiB, we silently * round down, otherwise we flag the issue. */ if (VIR_DIV_UP(def->mem.cur_balloon, 4096) > - VIR_DIV_UP(def->mem.max_balloon, 4096)) { + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 4096)) { virReportError(VIR_ERR_XML_ERROR, _("current memory '%lluk' exceeds " "maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def)); return -1; } 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; + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def)); + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); } } else if (def->mem.cur_balloon == 0) { - def->mem.cur_balloon = def->mem.max_balloon; + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); } /* @@ -6882,6 +6884,51 @@ virDomainParseMemory(const char *xpath, } +/** + * virDomainDefGetMemoryInitial: + * @def: domain definition + * + * Returns the size of the initial amount of guest memory. The initial amount + * is the memory size is either the configured amount in the <memory> element + * or the sum of memory sizes of NUMA nodes in case NUMA is enabled in @def. + */ +unsigned long long +virDomainDefGetMemoryInitial(virDomainDefPtr def) +{ + return def->mem.max_balloon; +} + + +/** + * virDomainDefSetMemoryInitial: + * @def: domain definition + * @size: size to set + * + * Sets the initial memory size in @def. + */ +void +virDomainDefSetMemoryInitial(virDomainDefPtr def, + unsigned long long size) +{ + def->mem.max_balloon = size; +} + + +/** + * virDomainDefGetMemoryCurrent: + * @def: domain definition + * + * Returns the current maximum memory size usable by the domain described by + * @def. This size is a sum of size returned by virDomainDefGetMemoryInitial + * and possible additional memory devices. + */ +unsigned long long +virDomainDefGetMemoryCurrent(virDomainDefPtr def) +{ + return virDomainDefGetMemoryInitial(def); +} + + static int virDomainControllerModelTypeFromString(const virDomainControllerDef *def, const char *model) @@ -15956,10 +16003,11 @@ virDomainDefCheckABIStability(virDomainDefPtr src, goto error; } - if (src->mem.max_balloon != dst->mem.max_balloon) { + if (virDomainDefGetMemoryInitial(src) != virDomainDefGetMemoryInitial(dst)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Target domain max memory %lld does not match source %lld"), - dst->mem.max_balloon, src->mem.max_balloon); + virDomainDefGetMemoryInitial(dst), + virDomainDefGetMemoryInitial(src)); goto error; } @@ -19652,7 +19700,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAsprintf(buf, " dumpCore='%s'", virTristateSwitchTypeToString(def->mem.dump_core)); virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n", - def->mem.max_balloon); + virDomainDefGetMemoryCurrent(def)); virBufferAsprintf(buf, "<currentMemory unit='KiB'>%llu</currentMemory>\n", def->mem.cur_balloon); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 86db2ab..7f9104e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2197,6 +2197,10 @@ struct _virDomainDef { xmlNodePtr metadata; }; +unsigned long long virDomainDefGetMemoryInitial(virDomainDefPtr def); +void virDomainDefSetMemoryInitial(virDomainDefPtr def, unsigned long long size); +unsigned long long virDomainDefGetMemoryCurrent(virDomainDefPtr def); + typedef enum { VIR_DOMAIN_TAINT_CUSTOM_ARGV, /* Custom ARGV passthrough from XML */ VIR_DOMAIN_TAINT_CUSTOM_MONITOR, /* Custom monitor commands issued */ diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 906c603..00169c7 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -870,7 +870,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) if (VIR_STRDUP(def->description, virtualSystemSettingData->data->Notes) < 0) goto cleanup; - def->mem.max_balloon = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */ + virDomainDefSetMemoryInitial(def, memorySettingData->data->Limit * 1024); /* megabyte to kilobyte */ def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */ def->vcpus = processorSettingData->data->VirtualQuantity; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c156b40..a58b2b9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -198,6 +198,8 @@ virDomainDefFormatConvertXMLFlags; virDomainDefFormatInternal; virDomainDefFree; virDomainDefGetDefaultEmulator; +virDomainDefGetMemoryCurrent; +virDomainDefGetMemoryInitial; virDomainDefGetSecurityLabelDef; virDomainDefHasDeviceAddress; virDomainDefMaybeAddController; @@ -209,6 +211,7 @@ virDomainDefParseFile; virDomainDefParseNode; virDomainDefParseString; virDomainDefPostParse; +virDomainDefSetMemoryInitial; virDomainDeleteConfig; virDomainDeviceAddressIsValid; virDomainDeviceAddressTypeToString; diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index e092b11..9389a8e 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -659,7 +659,7 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, } } b_info->sched_params.weight = 1000; - b_info->max_memkb = def->mem.max_balloon; + b_info->max_memkb = virDomainDefGetMemoryCurrent(def); b_info->target_memkb = def->mem.cur_balloon; if (hvm) { char bootorder[VIR_DOMAIN_BOOT_LAST + 1]; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index ce3a99b..8c04952 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1075,7 +1075,7 @@ libxlDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup; - ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def); cleanup: if (vm) @@ -1157,7 +1157,7 @@ libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, if (flags & VIR_DOMAIN_MEM_CONFIG) { /* Help clang 2.8 decipher the logic flow. */ sa_assert(persistentDef); - persistentDef->mem.max_balloon = newmem; + virDomainDefSetMemoryInitial(persistentDef, newmem); if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; ret = virDomainSaveConfig(cfg->configDir, persistentDef); @@ -1167,7 +1167,7 @@ libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } else { /* resize the current memory */ - if (newmem > vm->def->mem.max_balloon) { + if (newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set memory higher than max memory")); goto endjob; @@ -1241,7 +1241,7 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) if (!virDomainObjIsActive(vm)) { info->cpuTime = 0; info->memory = vm->def->mem.cur_balloon; - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); } else { if (libxl_domain_info(priv->ctx, &d_info, vm->def->id) != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 8e46a01..1d0ce56 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -146,7 +146,7 @@ static int virLXCCgroupSetupMemTune(virDomainDefPtr def, { int ret = -1; - if (virCgroupSetMemory(cgroup, def->mem.max_balloon) < 0) + if (virCgroupSetMemory(cgroup, virDomainDefGetMemoryCurrent(def)) < 0) goto cleanup; if (def->mem.hard_limit && diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 5af0554..bb8b78f 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -617,7 +617,7 @@ static int lxcDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->nrVirtCpu = vm->def->vcpus; ret = 0; @@ -686,7 +686,7 @@ lxcDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup; - ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def); cleanup: if (vm) @@ -735,7 +735,7 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - persistentDef->mem.max_balloon = newmem; + virDomainDefSetMemoryInitial(persistentDef, newmem); if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0) @@ -743,7 +743,7 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } } else { if (flags & VIR_DOMAIN_AFFECT_LIVE && - newmem > vm->def->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the live instance can't be less " "than the current memory")); @@ -751,7 +751,7 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } if (flags & VIR_DOMAIN_AFFECT_CONFIG && - newmem > persistentDef->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(persistentDef)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the persistent configuration can't " "be less than the current memory")); diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c index 5c18cff..c702363 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -165,11 +165,11 @@ static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def, *ptr = '\0'; if (STREQ(line, "MemTotal") && - (def->mem.hard_limit || def->mem.max_balloon)) { + (def->mem.hard_limit || virDomainDefGetMemoryCurrent(def))) { virBufferAsprintf(new_meminfo, "MemTotal: %8llu kB\n", meminfo.memtotal); } else if (STREQ(line, "MemFree") && - (def->mem.hard_limit || def->mem.max_balloon)) { + (def->mem.hard_limit || virDomainDefGetMemoryCurrent(def))) { virBufferAsprintf(new_meminfo, "MemFree: %8llu kB\n", (meminfo.memtotal - meminfo.memusage)); } else if (STREQ(line, "Buffers")) { diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index abf07ce..b3b72bc 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -772,7 +772,7 @@ lxcSetMemTune(virDomainDefPtr def, virConfPtr properties) if (lxcConvertSize(value->str, &size) < 0) return -1; size = size / 1024; - def->mem.max_balloon = size; + virDomainDefSetMemoryInitial(def, size); def->mem.hard_limit = size; } @@ -1012,7 +1012,7 @@ lxcParseConfigString(const char *config) } vmdef->id = -1; - vmdef->mem.max_balloon = 64 * 1024; + virDomainDefSetMemoryInitial(vmdef, 64 * 1024); vmdef->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; vmdef->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY; diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 5a5cd8d..236d372 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -458,7 +458,7 @@ static int openvzDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index c9338b5..b73a98d 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -522,7 +522,7 @@ parallelsDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) info->state = virDomainObjGetState(privdom, NULL); info->memory = privdom->def->mem.cur_balloon; - info->maxMem = privdom->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(privdom->def); info->nrVirtCpu = privdom->def->vcpus; info->cpuTime = 0; ret = 0; diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index d5ea00a..eed056e 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -1213,9 +1213,9 @@ prlsdkLoadDomain(parallelsConnPtr privconn, /* get RAM parameters */ pret = PrlVmCfg_GetRamSize(sdkdom, &ram); prlsdkCheckRetGoto(pret, error); - def->mem.max_balloon = ram << 10; /* RAM size obtained in Mbytes, - convert to Kbytes */ - def->mem.cur_balloon = def->mem.max_balloon; + virDomainDefSetMemoryInitial(def, ram << 10); /* RAM size obtained in Mbytes, + convert to Kbytes */ + def->mem.cur_balloon = ram << 10; if (prlsdkConvertCpuInfo(sdkdom, def, pdom) < 0) goto error; @@ -1769,14 +1769,14 @@ prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def) return -1; } - if (def->mem.max_balloon != def->mem.cur_balloon) { + if (virDomainDefGetMemoryCurrent(def) != def->mem.cur_balloon) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("changing balloon parameters is not supported " "by parallels driver")); return -1; } - if (def->mem.max_balloon % (1 << 10) != 0) { + if (virDomainDefGetMemoryCurrent(def) % (1 << 10) != 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Memory size should be multiple of 1Mb.")); return -1; @@ -2788,7 +2788,7 @@ prlsdkDoApplyConfig(PRL_HANDLE sdkdom, prlsdkCheckRetGoto(pret, error); } - pret = PrlVmCfg_SetRamSize(sdkdom, def->mem.max_balloon >> 10); + pret = PrlVmCfg_SetRamSize(sdkdom, virDomainDefGetMemoryCurrent(def) >> 10); prlsdkCheckRetGoto(pret, error); pret = PrlVmCfg_SetCpuCount(sdkdom, def->vcpus); diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index d69e29c..9853bfe 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3252,6 +3252,7 @@ phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) LIBSSH2_SESSION *session = phyp_driver->session; virDomainDef def; char *managed_system = phyp_driver->managed_system; + unsigned long long memory; /* Flags checked by virDomainDefFormat */ @@ -3273,12 +3274,13 @@ phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) goto err; } - if ((def.mem.max_balloon = - phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) { + if ((memory = phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) { VIR_ERROR(_("Unable to determine domain's max memory.")); goto err; } + virDomainDefSetMemoryInitial(&def, memory); + if ((def.mem.cur_balloon = phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) { VIR_ERROR(_("Unable to determine domain's memory.")); @@ -3491,7 +3493,7 @@ phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) goto cleanup; } - if (!def->mem.max_balloon) { + if (!virDomainDefGetMemoryCurrent(def)) { virReportError(VIR_ERR_XML_ERROR, "%s", _("Field <currentMemory> on the domain XML file is missing or " "has invalid value.")); @@ -3517,7 +3519,8 @@ phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) virBufferAsprintf(&buf, " -r lpar -p %s -i min_mem=%lld,desired_mem=%lld," "max_mem=%lld,desired_procs=%d,virtual_scsi_adapters=%s", def->name, def->mem.cur_balloon, - def->mem.cur_balloon, def->mem.max_balloon, + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def), (int) def->vcpus, virDomainDiskGetSource(def->disks[0])); ret = phypExecBuffer(session, &buf, &exit_status, conn, false); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7853125..bf47702 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8319,8 +8319,9 @@ qemuBuildCommandLine(virConnectPtr conn, * XML to reflect our rounding. */ virCommandAddArg(cmd, "-m"); - def->mem.max_balloon = VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024; - virCommandAddArgFormat(cmd, "%llu", def->mem.max_balloon / 1024); + virDomainDefSetMemoryInitial(def, VIR_ROUND_UP(virDomainDefGetMemoryInitial(def), 1024)); + virCommandAddArgFormat(cmd, "%llu", virDomainDefGetMemoryInitial(def) / 1024); + if (def->mem.nhugepages && !virDomainNumaGetNodeCount(def->numa)) { const long system_page_size = virGetSystemPageSizeKB(); char *mem_path = NULL; @@ -10335,8 +10336,11 @@ qemuBuildCommandLine(virConnectPtr conn, * space just to be safe (some finer tuning might be * nice, though). */ - memKB = def->mem.hard_limit ? - def->mem.hard_limit : def->mem.max_balloon + 1024 * 1024; + if (def->mem.hard_limit) + memKB = def->mem.hard_limit; + else + memKB = virDomainDefGetMemoryCurrent(def) + 1024 * 1024; + virCommandSetMaxMemLock(cmd, memKB * 1024); } @@ -11888,7 +11892,8 @@ qemuParseCommandLine(virCapsPtr qemuCaps, } def->id = -1; - def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024; + def->mem.cur_balloon = 64 * 1024; + virDomainDefSetMemoryInitial(def, def->mem.cur_balloon); def->maxvcpus = 1; def->vcpus = 1; def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; @@ -12096,7 +12101,8 @@ qemuParseCommandLine(virCapsPtr qemuCaps, _("cannot parse memory level '%s'"), val); goto error; } - def->mem.cur_balloon = def->mem.max_balloon = mem * 1024; + virDomainDefSetMemoryInitial(def, mem * 1024); + def->mem.cur_balloon = mem * 1024; } else if (STREQ(arg, "-smp")) { WANT_VALUE(); if (qemuParseCommandLineSmp(def, val) < 0) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4458e02..78424a4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2255,7 +2255,7 @@ qemuDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup; - ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def); cleanup: qemuDomObjEndAPI(&vm); @@ -2317,7 +2317,8 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, goto endjob; } - persistentDef->mem.max_balloon = newmem; + virDomainDefSetMemoryInitial(persistentDef, newmem); + if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; ret = virDomainSaveConfig(cfg->configDir, persistentDef); @@ -2327,7 +2328,7 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } else { /* resize the current memory */ if (flags & VIR_DOMAIN_AFFECT_LIVE && - newmem > vm->def->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the live instance can't be less " "than the current memory")); @@ -2335,7 +2336,7 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } if (flags & VIR_DOMAIN_AFFECT_CONFIG && - newmem > persistentDef->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(persistentDef)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the persistent configuration can't " "be less than the current memory")); @@ -2595,14 +2596,14 @@ static int qemuDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); if (virDomainObjIsActive(vm)) { qemuDomainObjPrivatePtr priv = vm->privateData; if ((vm->def->memballoon != NULL) && (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) { - info->memory = vm->def->mem.max_balloon; + info->memory = virDomainDefGetMemoryCurrent(vm->def); } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) { info->memory = vm->def->mem.cur_balloon; } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) { @@ -2628,7 +2629,7 @@ static int qemuDomainGetInfo(virDomainPtr dom, info->memory = vm->def->mem.cur_balloon; } else if (err == 0) { /* Balloon not supported, so maxmem is always the allocation */ - info->memory = vm->def->mem.max_balloon; + info->memory = virDomainDefGetMemoryCurrent(vm->def); } else { info->memory = balloon; } @@ -18428,7 +18429,7 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (dom->def->memballoon && dom->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE) { - cur_balloon = dom->def->mem.max_balloon; + cur_balloon = virDomainDefGetMemoryCurrent(dom->def); } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) { cur_balloon = dom->def->mem.cur_balloon; } else { @@ -18446,7 +18447,7 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, &record->nparams, maxparams, "balloon.maximum", - dom->def->mem.max_balloon) < 0) + virDomainDefGetMemoryCurrent(dom->def)) < 0) return -1; return 0; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 8691c7e..8d91719 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1252,9 +1252,11 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver, * Kibibytes, but virProcessSetMaxMemLock expects the value in * bytes. */ - memKB = vm->def->mem.hard_limit - ? vm->def->mem.hard_limit - : vm->def->mem.max_balloon + (1024 * 1024); + if (vm->def->mem.hard_limit) + memKB = vm->def->mem.hard_limit; + else + memKB = virDomainDefGetMemoryCurrent(vm->def) + (1024 * 1024); + virProcessSetMaxMemLock(vm->pid, memKB * 1024); break; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 61790f4..31ec8eb 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4624,7 +4624,7 @@ int qemuProcessStart(virConnectPtr conn, */ if (virDomainDefNeedsPlacementAdvice(vm->def)) { nodeset = virNumaGetAutoPlacementAdvice(vm->def->vcpus, - vm->def->mem.max_balloon); + virDomainDefGetMemoryCurrent(vm->def)); if (!nodeset) goto cleanup; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index a386270..3aa6a5e 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -2149,7 +2149,7 @@ static int testDomainGetInfo(virDomainPtr domain, info->state = virDomainObjGetState(privdom, NULL); info->memory = privdom->def->mem.cur_balloon; - info->maxMem = privdom->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(privdom->def); info->nrVirtCpu = privdom->def->vcpus; info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); ret = 0; @@ -2517,7 +2517,7 @@ testDomainGetMaxMemory(virDomainPtr domain) goto cleanup; } - ret = privdom->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(privdom->def); cleanup: if (privdom) @@ -2543,7 +2543,7 @@ static int testDomainSetMaxMemory(virDomainPtr domain, } /* XXX validate not over host memory wrt to other domains */ - privdom->def->mem.max_balloon = memory; + virDomainDefSetMemoryInitial(privdom->def, memory); ret = 0; cleanup: @@ -2569,7 +2569,7 @@ static int testDomainSetMemory(virDomainPtr domain, goto cleanup; } - if (memory > privdom->def->mem.max_balloon) { + if (memory > virDomainDefGetMemoryCurrent(privdom->def)) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 68efd18..59ff33c 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1802,7 +1802,7 @@ umlDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup; - ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def); cleanup: if (vm) @@ -1838,7 +1838,7 @@ static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) goto cleanup; } - vm->def->mem.max_balloon = newmax; + virDomainDefSetMemoryInitial(vm->def, newmax); ret = 0; cleanup: @@ -1875,7 +1875,7 @@ static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) goto cleanup; } - if (newmem > vm->def->mem.max_balloon) { + if (newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set memory higher than max memory")); goto cleanup; @@ -1922,7 +1922,7 @@ static int umlDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index 55d3624..6697ecc 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -3894,7 +3894,7 @@ static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) * reading and while dumping xml */ /* def->mem.max_balloon = maxMemorySize * 1024; */ - def->mem.max_balloon = memorySize * 1024; + virDomainDefSetMemoryInitial(def, memorySize * 1024); gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount); def->maxvcpus = def->vcpus = CPUCount; @@ -6055,7 +6055,7 @@ static char *vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, * the notation here seems to be inconsistent while * reading and while dumping xml */ - def->dom->mem.max_balloon = memorySize * 1024; + virDomainDefSetMemoryInitial(def->dom, memorySize * 1024); if (VIR_STRDUP(def->dom->os.type, "hvm") < 0) goto cleanup; def->dom->os.arch = virArchFromHost(); diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index fb7fa5b..71589a6 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -1126,7 +1126,7 @@ vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) info->state = virDomainObjGetState(vm, NULL); info->cpuTime = 0; - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index ac2542a..eba1a68 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -1375,7 +1375,7 @@ virVMXParseConfig(virVMXContext *ctx, goto cleanup; } - def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */ + virDomainDefSetMemoryInitial(def, memsize * 1024); /* Scale from megabytes to kilobytes */ /* vmx:sched.mem.max -> def:mem.cur_balloon */ if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize, @@ -1388,8 +1388,8 @@ virVMXParseConfig(virVMXContext *ctx, def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */ - if (def->mem.cur_balloon > def->mem.max_balloon) - def->mem.cur_balloon = def->mem.max_balloon; + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); /* vmx:sched.mem.minsize -> def:mem.min_guarantee */ if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0, @@ -1402,8 +1402,8 @@ virVMXParseConfig(virVMXContext *ctx, def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */ - if (def->mem.min_guarantee > def->mem.max_balloon) - def->mem.min_guarantee = def->mem.max_balloon; + if (def->mem.min_guarantee > virDomainDefGetMemoryCurrent(def)) + def->mem.min_guarantee = virDomainDefGetMemoryCurrent(def); /* vmx:numvcpus -> def:vcpus */ if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) @@ -3083,7 +3083,7 @@ virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virDomainDe /* def:mem.max_balloon -> vmx:memsize */ /* max-memory must be a multiple of 4096 kilobyte */ - max_balloon = VIR_DIV_UP(def->mem.max_balloon, 4096) * 4096; + max_balloon = VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 4096) * 4096; virBufferAsprintf(&buffer, "memsize = \"%llu\"\n", max_balloon / 1024); /* Scale from kilobytes to megabytes */ diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 354ab3f..ab9e6a6 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -479,7 +479,7 @@ xenXMDomainGetInfo(virConnectPtr conn, goto error; memset(info, 0, sizeof(virDomainInfo)); - info->maxMem = entry->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(entry->def); info->memory = entry->def->mem.cur_balloon; info->nrVirtCpu = entry->def->vcpus; info->state = VIR_DOMAIN_SHUTOFF; @@ -557,8 +557,8 @@ xenXMDomainSetMemory(virConnectPtr conn, goto cleanup; entry->def->mem.cur_balloon = memory; - if (entry->def->mem.cur_balloon > entry->def->mem.max_balloon) - entry->def->mem.cur_balloon = entry->def->mem.max_balloon; + if (entry->def->mem.cur_balloon > virDomainDefGetMemoryCurrent(entry->def)) + entry->def->mem.cur_balloon = virDomainDefGetMemoryCurrent(entry->def); /* If this fails, should we try to undo our changes to the * in-memory representation of the config file. I say not! @@ -600,10 +600,10 @@ xenXMDomainSetMaxMemory(virConnectPtr conn, if (!(entry = virHashLookup(priv->configCache, filename))) goto cleanup; - entry->def->mem.max_balloon = memory; - if (entry->def->mem.cur_balloon > entry->def->mem.max_balloon) - entry->def->mem.cur_balloon = entry->def->mem.max_balloon; + if (entry->def->mem.cur_balloon > memory) + entry->def->mem.cur_balloon = memory; + virDomainDefSetMemoryInitial(entry->def, memory); /* If this fails, should we try to undo our changes to the * in-memory representation of the config file. I say not! */ @@ -636,7 +636,7 @@ xenXMDomainGetMaxMemory(virConnectPtr conn, if (!(entry = virHashLookup(priv->configCache, filename))) goto cleanup; - ret = entry->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(entry->def); cleanup: xenUnifiedUnlock(priv); diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index afb6d6c..b3dd852 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1490,7 +1490,7 @@ xenapiDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) VIR_FREE(val); } memory = xenapiDomainGetMaxMemory(dom); - defPtr->mem.max_balloon = memory; + virDomainDefSetMemoryInitial(defPtr, memory); if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { defPtr->mem.cur_balloon = (unsigned long) (dynamic_mem / 1024); } else { diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 91bc649..35f0f04 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -495,8 +495,8 @@ createVMRecordFromXml(virConnectPtr conn, virDomainDefPtr def, if (def->mem.cur_balloon) (*record)->memory_static_max = (int64_t) (def->mem.cur_balloon * 1024); - if (def->mem.max_balloon) - (*record)->memory_dynamic_max = (int64_t) (def->mem.max_balloon * 1024); + if (virDomainDefGetMemoryCurrent(def)) + (*record)->memory_dynamic_max = (int64_t) (virDomainDefGetMemoryCurrent(def) * 1024); else (*record)->memory_dynamic_max = (*record)->memory_static_max; diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c index a2a1474..924f0d6 100644 --- a/src/xenconfig/xen_common.c +++ b/src/xenconfig/xen_common.c @@ -305,16 +305,18 @@ xenConfigSetString(virConfPtr conf, const char *setting, const char *str) static int xenParseMem(virConfPtr conf, virDomainDefPtr def) { + unsigned long long memory; + if (xenConfigGetULongLong(conf, "memory", &def->mem.cur_balloon, MIN_XEN_GUEST_SIZE * 2) < 0) return -1; - if (xenConfigGetULongLong(conf, "maxmem", &def->mem.max_balloon, + if (xenConfigGetULongLong(conf, "maxmem", &memory, def->mem.cur_balloon) < 0) return -1; def->mem.cur_balloon *= 1024; - def->mem.max_balloon *= 1024; + virDomainDefSetMemoryInitial(def, memory * 1024); return 0; } @@ -1410,7 +1412,7 @@ static int xenFormatMem(virConfPtr conf, virDomainDefPtr def) { if (xenConfigSetInt(conf, "maxmem", - VIR_DIV_UP(def->mem.max_balloon, 1024)) < 0) + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 1024)) < 0) return -1; if (xenConfigSetInt(conf, "memory", diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c index 3e18a7e..fbebf51 100644 --- a/src/xenconfig/xen_sxpr.c +++ b/src/xenconfig/xen_sxpr.c @@ -1155,10 +1155,11 @@ xenParseSxpr(const struct sexpr *root, } } - def->mem.max_balloon = (sexpr_u64(root, "domain/maxmem") << 10); + virDomainDefSetMemoryInitial(def, (sexpr_u64(root, "domain/maxmem") << 10)); def->mem.cur_balloon = (sexpr_u64(root, "domain/memory") << 10); - if (def->mem.cur_balloon > def->mem.max_balloon) - def->mem.cur_balloon = def->mem.max_balloon; + + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); if (cpus != NULL) { if (virBitmapParse(cpus, 0, &def->cpumask, @@ -2213,7 +2214,7 @@ xenFormatSxpr(virConnectPtr conn, virBufferEscapeSexpr(&buf, "(name '%s')", def->name); virBufferAsprintf(&buf, "(memory %llu)(maxmem %llu)", VIR_DIV_UP(def->mem.cur_balloon, 1024), - VIR_DIV_UP(def->mem.max_balloon, 1024)); + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 1024)); virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus); /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is either 32, or 64 on a platform where long is big enough. */ -- 2.2.2

On 02/18/2015 09:16 AM, Peter Krempa wrote:
As there are two possible approaches to define a domain's memory size - one used with legacy, non-NUMA VMs configured in the <memory> element and per-node based approach on NUMA machines - the user needs to make sure that both are specified correctly in the NUMA case.
To avoid this burden on the user I'd like to replace the NUMA case with automatic totaling of the memory size. To achieve this I need to replace direct access to the virDomainMemtune's 'max_balloon' field with two separate getters depending on the desired size.
The two sizes are needed as: 1) Startup memory size doesn't include memory modules in some hypervisors. 2) After startup these count as the usable memory size.
Note that the comments for the functions are future aware and document state that will be present after a few later patches. --- src/conf/domain_conf.c | 66 ++++++++++++++++++++++++++++++++++------ src/conf/domain_conf.h | 4 +++ src/hyperv/hyperv_driver.c | 2 +- src/libvirt_private.syms | 3 ++ src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 8 ++--- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_driver.c | 10 +++--- src/lxc/lxc_fuse.c | 4 +-- src/lxc/lxc_native.c | 4 +-- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_sdk.c | 12 ++++---- src/phyp/phyp_driver.c | 11 ++++--- src/qemu/qemu_command.c | 18 +++++++---- src/qemu/qemu_driver.c | 19 ++++++------ src/qemu/qemu_hotplug.c | 8 +++-- src/qemu/qemu_process.c | 2 +- src/test/test_driver.c | 8 ++--- src/uml/uml_driver.c | 8 ++--- src/vbox/vbox_common.c | 4 +-- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 12 ++++---- src/xen/xm_internal.c | 14 ++++----- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 4 +-- src/xenconfig/xen_common.c | 8 +++-- src/xenconfig/xen_sxpr.c | 9 +++--- 28 files changed, 160 insertions(+), 90 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6ef499d..e95851a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3172,24 +3172,26 @@ virDomainDefPostParseInternal(virDomainDefPtr def, return -1; }
- if (def->mem.cur_balloon > def->mem.max_balloon) { + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) { /* Older libvirt could get into this situation due to * rounding; if the discrepancy is less than 4MiB, we silently * round down, otherwise we flag the issue. */ if (VIR_DIV_UP(def->mem.cur_balloon, 4096) > - VIR_DIV_UP(def->mem.max_balloon, 4096)) { + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 4096)) { virReportError(VIR_ERR_XML_ERROR, _("current memory '%lluk' exceeds " "maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def)); return -1; } 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; + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def)); + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); } } else if (def->mem.cur_balloon == 0) { - def->mem.cur_balloon = def->mem.max_balloon; + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); }
/* @@ -6882,6 +6884,51 @@ virDomainParseMemory(const char *xpath, }
+/** + * virDomainDefGetMemoryInitial: + * @def: domain definition + * + * Returns the size of the initial amount of guest memory. The initial amount + * is the memory size is either the configured amount in the <memory> element + * or the sum of memory sizes of NUMA nodes in case NUMA is enabled in @def. + */ +unsigned long long +virDomainDefGetMemoryInitial(virDomainDefPtr def) +{ + return def->mem.max_balloon; +} + + +/** + * virDomainDefSetMemoryInitial: + * @def: domain definition + * @size: size to set + * + * Sets the initial memory size in @def. + */ +void +virDomainDefSetMemoryInitial(virDomainDefPtr def, + unsigned long long size) +{ + def->mem.max_balloon = size; +}
Odd concept - changing Initial memory, but I don't have a better name in mind...
+ + +/** + * virDomainDefGetMemoryCurrent: + * @def: domain definition + * + * Returns the current maximum memory size usable by the domain described by + * @def. This size is a sum of size returned by virDomainDefGetMemoryInitial + * and possible additional memory devices. + */ +unsigned long long +virDomainDefGetMemoryCurrent(virDomainDefPtr def) +{ + return virDomainDefGetMemoryInitial(def); +}
Ok - so part of me expect this one to return mem.cur_balloon - perhaps a name change to GetMemoryUsable would help? and of course begs the question why not bite the bullet and return mem.cur_balloon in a GetMemoryCurrent accessor...
+ + static int virDomainControllerModelTypeFromString(const virDomainControllerDef *def, const char *model) @@ -15956,10 +16003,11 @@ virDomainDefCheckABIStability(virDomainDefPtr src, goto error; }
- if (src->mem.max_balloon != dst->mem.max_balloon) { + if (virDomainDefGetMemoryInitial(src) != virDomainDefGetMemoryInitial(dst)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Target domain max memory %lld does not match source %lld"), - dst->mem.max_balloon, src->mem.max_balloon); + virDomainDefGetMemoryInitial(dst), + virDomainDefGetMemoryInitial(src)); goto error; }
Since the "future" (I assume) is that MemoryCurrent will include the hot (un)plug memory - does it make sense to also compare src/dst MemoryCurrent values even though for now it's essentially the same value? Although I believe that gets done in your later series and it's hard to keep them in my memory. Of the remaining uses of GetInitial and {Get|Set}Current the ones I was wondering about are: virLXCCgroupSetupMemTune libxlMakeDomBuildInfo phypBuildLpar Wouldn't they be the corollary to qemuBuildCommandLine w/r/t using Initial instead of Current in order to define the memory for the guest as it starts up? John
@@ -19652,7 +19700,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAsprintf(buf, " dumpCore='%s'", virTristateSwitchTypeToString(def->mem.dump_core)); virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n", - def->mem.max_balloon); + virDomainDefGetMemoryCurrent(def));
virBufferAsprintf(buf, "<currentMemory unit='KiB'>%llu</currentMemory>\n", def->mem.cur_balloon); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 86db2ab..7f9104e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2197,6 +2197,10 @@ struct _virDomainDef { xmlNodePtr metadata; };
+unsigned long long virDomainDefGetMemoryInitial(virDomainDefPtr def); +void virDomainDefSetMemoryInitial(virDomainDefPtr def, unsigned long long size); +unsigned long long virDomainDefGetMemoryCurrent(virDomainDefPtr def); + typedef enum { VIR_DOMAIN_TAINT_CUSTOM_ARGV, /* Custom ARGV passthrough from XML */ VIR_DOMAIN_TAINT_CUSTOM_MONITOR, /* Custom monitor commands issued */ diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 906c603..00169c7 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -870,7 +870,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) if (VIR_STRDUP(def->description, virtualSystemSettingData->data->Notes) < 0) goto cleanup;
- def->mem.max_balloon = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */ + virDomainDefSetMemoryInitial(def, memorySettingData->data->Limit * 1024); /* megabyte to kilobyte */ def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
def->vcpus = processorSettingData->data->VirtualQuantity; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c156b40..a58b2b9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -198,6 +198,8 @@ virDomainDefFormatConvertXMLFlags; virDomainDefFormatInternal; virDomainDefFree; virDomainDefGetDefaultEmulator; +virDomainDefGetMemoryCurrent; +virDomainDefGetMemoryInitial; virDomainDefGetSecurityLabelDef; virDomainDefHasDeviceAddress; virDomainDefMaybeAddController; @@ -209,6 +211,7 @@ virDomainDefParseFile; virDomainDefParseNode; virDomainDefParseString; virDomainDefPostParse; +virDomainDefSetMemoryInitial; virDomainDeleteConfig; virDomainDeviceAddressIsValid; virDomainDeviceAddressTypeToString; diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index e092b11..9389a8e 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -659,7 +659,7 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, } } b_info->sched_params.weight = 1000; - b_info->max_memkb = def->mem.max_balloon; + b_info->max_memkb = virDomainDefGetMemoryCurrent(def); b_info->target_memkb = def->mem.cur_balloon; if (hvm) { char bootorder[VIR_DOMAIN_BOOT_LAST + 1]; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index ce3a99b..8c04952 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1075,7 +1075,7 @@ libxlDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup;
- ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def);
cleanup: if (vm) @@ -1157,7 +1157,7 @@ libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, if (flags & VIR_DOMAIN_MEM_CONFIG) { /* Help clang 2.8 decipher the logic flow. */ sa_assert(persistentDef); - persistentDef->mem.max_balloon = newmem; + virDomainDefSetMemoryInitial(persistentDef, newmem); if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; ret = virDomainSaveConfig(cfg->configDir, persistentDef); @@ -1167,7 +1167,7 @@ libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } else { /* resize the current memory */
- if (newmem > vm->def->mem.max_balloon) { + if (newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set memory higher than max memory")); goto endjob; @@ -1241,7 +1241,7 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) if (!virDomainObjIsActive(vm)) { info->cpuTime = 0; info->memory = vm->def->mem.cur_balloon; - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); } else { if (libxl_domain_info(priv->ctx, &d_info, vm->def->id) != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 8e46a01..1d0ce56 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -146,7 +146,7 @@ static int virLXCCgroupSetupMemTune(virDomainDefPtr def, { int ret = -1;
- if (virCgroupSetMemory(cgroup, def->mem.max_balloon) < 0) + if (virCgroupSetMemory(cgroup, virDomainDefGetMemoryCurrent(def)) < 0) goto cleanup;
if (def->mem.hard_limit && diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 5af0554..bb8b78f 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -617,7 +617,7 @@ static int lxcDomainGetInfo(virDomainPtr dom, } }
- info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->nrVirtCpu = vm->def->vcpus; ret = 0;
@@ -686,7 +686,7 @@ lxcDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup;
- ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def);
cleanup: if (vm) @@ -735,7 +735,7 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, }
if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - persistentDef->mem.max_balloon = newmem; + virDomainDefSetMemoryInitial(persistentDef, newmem); if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0) @@ -743,7 +743,7 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } } else { if (flags & VIR_DOMAIN_AFFECT_LIVE && - newmem > vm->def->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the live instance can't be less " "than the current memory")); @@ -751,7 +751,7 @@ static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, }
if (flags & VIR_DOMAIN_AFFECT_CONFIG && - newmem > persistentDef->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(persistentDef)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the persistent configuration can't " "be less than the current memory")); diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c index 5c18cff..c702363 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -165,11 +165,11 @@ static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def, *ptr = '\0';
if (STREQ(line, "MemTotal") && - (def->mem.hard_limit || def->mem.max_balloon)) { + (def->mem.hard_limit || virDomainDefGetMemoryCurrent(def))) { virBufferAsprintf(new_meminfo, "MemTotal: %8llu kB\n", meminfo.memtotal); } else if (STREQ(line, "MemFree") && - (def->mem.hard_limit || def->mem.max_balloon)) { + (def->mem.hard_limit || virDomainDefGetMemoryCurrent(def))) { virBufferAsprintf(new_meminfo, "MemFree: %8llu kB\n", (meminfo.memtotal - meminfo.memusage)); } else if (STREQ(line, "Buffers")) { diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index abf07ce..b3b72bc 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -772,7 +772,7 @@ lxcSetMemTune(virDomainDefPtr def, virConfPtr properties) if (lxcConvertSize(value->str, &size) < 0) return -1; size = size / 1024; - def->mem.max_balloon = size; + virDomainDefSetMemoryInitial(def, size); def->mem.hard_limit = size; }
@@ -1012,7 +1012,7 @@ lxcParseConfigString(const char *config) }
vmdef->id = -1; - vmdef->mem.max_balloon = 64 * 1024; + virDomainDefSetMemoryInitial(vmdef, 64 * 1024);
vmdef->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; vmdef->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY; diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 5a5cd8d..236d372 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -458,7 +458,7 @@ static int openvzDomainGetInfo(virDomainPtr dom, } }
- info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index c9338b5..b73a98d 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -522,7 +522,7 @@ parallelsDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
info->state = virDomainObjGetState(privdom, NULL); info->memory = privdom->def->mem.cur_balloon; - info->maxMem = privdom->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(privdom->def); info->nrVirtCpu = privdom->def->vcpus; info->cpuTime = 0; ret = 0; diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index d5ea00a..eed056e 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -1213,9 +1213,9 @@ prlsdkLoadDomain(parallelsConnPtr privconn, /* get RAM parameters */ pret = PrlVmCfg_GetRamSize(sdkdom, &ram); prlsdkCheckRetGoto(pret, error); - def->mem.max_balloon = ram << 10; /* RAM size obtained in Mbytes, - convert to Kbytes */ - def->mem.cur_balloon = def->mem.max_balloon; + virDomainDefSetMemoryInitial(def, ram << 10); /* RAM size obtained in Mbytes, + convert to Kbytes */ + def->mem.cur_balloon = ram << 10;
if (prlsdkConvertCpuInfo(sdkdom, def, pdom) < 0) goto error; @@ -1769,14 +1769,14 @@ prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def) return -1; }
- if (def->mem.max_balloon != def->mem.cur_balloon) { + if (virDomainDefGetMemoryCurrent(def) != def->mem.cur_balloon) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("changing balloon parameters is not supported " "by parallels driver")); return -1; }
- if (def->mem.max_balloon % (1 << 10) != 0) { + if (virDomainDefGetMemoryCurrent(def) % (1 << 10) != 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Memory size should be multiple of 1Mb.")); return -1; @@ -2788,7 +2788,7 @@ prlsdkDoApplyConfig(PRL_HANDLE sdkdom, prlsdkCheckRetGoto(pret, error); }
- pret = PrlVmCfg_SetRamSize(sdkdom, def->mem.max_balloon >> 10); + pret = PrlVmCfg_SetRamSize(sdkdom, virDomainDefGetMemoryCurrent(def) >> 10); prlsdkCheckRetGoto(pret, error);
pret = PrlVmCfg_SetCpuCount(sdkdom, def->vcpus); diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index d69e29c..9853bfe 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3252,6 +3252,7 @@ phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) LIBSSH2_SESSION *session = phyp_driver->session; virDomainDef def; char *managed_system = phyp_driver->managed_system; + unsigned long long memory;
/* Flags checked by virDomainDefFormat */
@@ -3273,12 +3274,13 @@ phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) goto err; }
- if ((def.mem.max_balloon = - phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) { + if ((memory = phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) { VIR_ERROR(_("Unable to determine domain's max memory.")); goto err; }
+ virDomainDefSetMemoryInitial(&def, memory); + if ((def.mem.cur_balloon = phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) { VIR_ERROR(_("Unable to determine domain's memory.")); @@ -3491,7 +3493,7 @@ phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) goto cleanup; }
- if (!def->mem.max_balloon) { + if (!virDomainDefGetMemoryCurrent(def)) { virReportError(VIR_ERR_XML_ERROR, "%s", _("Field <currentMemory> on the domain XML file is missing or " "has invalid value.")); @@ -3517,7 +3519,8 @@ phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) virBufferAsprintf(&buf, " -r lpar -p %s -i min_mem=%lld,desired_mem=%lld," "max_mem=%lld,desired_procs=%d,virtual_scsi_adapters=%s", def->name, def->mem.cur_balloon, - def->mem.cur_balloon, def->mem.max_balloon, + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def), (int) def->vcpus, virDomainDiskGetSource(def->disks[0])); ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7853125..bf47702 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8319,8 +8319,9 @@ qemuBuildCommandLine(virConnectPtr conn, * XML to reflect our rounding. */ virCommandAddArg(cmd, "-m"); - def->mem.max_balloon = VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024; - virCommandAddArgFormat(cmd, "%llu", def->mem.max_balloon / 1024); + virDomainDefSetMemoryInitial(def, VIR_ROUND_UP(virDomainDefGetMemoryInitial(def), 1024)); + virCommandAddArgFormat(cmd, "%llu", virDomainDefGetMemoryInitial(def) / 1024); + if (def->mem.nhugepages && !virDomainNumaGetNodeCount(def->numa)) { const long system_page_size = virGetSystemPageSizeKB(); char *mem_path = NULL; @@ -10335,8 +10336,11 @@ qemuBuildCommandLine(virConnectPtr conn, * space just to be safe (some finer tuning might be * nice, though). */ - memKB = def->mem.hard_limit ? - def->mem.hard_limit : def->mem.max_balloon + 1024 * 1024; + if (def->mem.hard_limit) + memKB = def->mem.hard_limit; + else + memKB = virDomainDefGetMemoryCurrent(def) + 1024 * 1024; + virCommandSetMaxMemLock(cmd, memKB * 1024); }
@@ -11888,7 +11892,8 @@ qemuParseCommandLine(virCapsPtr qemuCaps, }
def->id = -1; - def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024; + def->mem.cur_balloon = 64 * 1024; + virDomainDefSetMemoryInitial(def, def->mem.cur_balloon); def->maxvcpus = 1; def->vcpus = 1; def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; @@ -12096,7 +12101,8 @@ qemuParseCommandLine(virCapsPtr qemuCaps, _("cannot parse memory level '%s'"), val); goto error; } - def->mem.cur_balloon = def->mem.max_balloon = mem * 1024; + virDomainDefSetMemoryInitial(def, mem * 1024); + def->mem.cur_balloon = mem * 1024; } else if (STREQ(arg, "-smp")) { WANT_VALUE(); if (qemuParseCommandLineSmp(def, val) < 0) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4458e02..78424a4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2255,7 +2255,7 @@ qemuDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup;
- ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def);
cleanup: qemuDomObjEndAPI(&vm); @@ -2317,7 +2317,8 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, goto endjob; }
- persistentDef->mem.max_balloon = newmem; + virDomainDefSetMemoryInitial(persistentDef, newmem); + if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; ret = virDomainSaveConfig(cfg->configDir, persistentDef); @@ -2327,7 +2328,7 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } else { /* resize the current memory */ if (flags & VIR_DOMAIN_AFFECT_LIVE && - newmem > vm->def->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the live instance can't be less " "than the current memory")); @@ -2335,7 +2336,7 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, }
if (flags & VIR_DOMAIN_AFFECT_CONFIG && - newmem > persistentDef->mem.max_balloon) { + newmem > virDomainDefGetMemoryCurrent(persistentDef)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("max memory of the persistent configuration can't " "be less than the current memory")); @@ -2595,14 +2596,14 @@ static int qemuDomainGetInfo(virDomainPtr dom, } }
- info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def);
if (virDomainObjIsActive(vm)) { qemuDomainObjPrivatePtr priv = vm->privateData;
if ((vm->def->memballoon != NULL) && (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) { - info->memory = vm->def->mem.max_balloon; + info->memory = virDomainDefGetMemoryCurrent(vm->def); } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) { info->memory = vm->def->mem.cur_balloon; } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) { @@ -2628,7 +2629,7 @@ static int qemuDomainGetInfo(virDomainPtr dom, info->memory = vm->def->mem.cur_balloon; } else if (err == 0) { /* Balloon not supported, so maxmem is always the allocation */ - info->memory = vm->def->mem.max_balloon; + info->memory = virDomainDefGetMemoryCurrent(vm->def); } else { info->memory = balloon; } @@ -18428,7 +18429,7 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
if (dom->def->memballoon && dom->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE) { - cur_balloon = dom->def->mem.max_balloon; + cur_balloon = virDomainDefGetMemoryCurrent(dom->def); } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) { cur_balloon = dom->def->mem.cur_balloon; } else { @@ -18446,7 +18447,7 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, &record->nparams, maxparams, "balloon.maximum", - dom->def->mem.max_balloon) < 0) + virDomainDefGetMemoryCurrent(dom->def)) < 0) return -1;
return 0; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 8691c7e..8d91719 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1252,9 +1252,11 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver, * Kibibytes, but virProcessSetMaxMemLock expects the value in * bytes. */ - memKB = vm->def->mem.hard_limit - ? vm->def->mem.hard_limit - : vm->def->mem.max_balloon + (1024 * 1024); + if (vm->def->mem.hard_limit) + memKB = vm->def->mem.hard_limit; + else + memKB = virDomainDefGetMemoryCurrent(vm->def) + (1024 * 1024); + virProcessSetMaxMemLock(vm->pid, memKB * 1024); break;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 61790f4..31ec8eb 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4624,7 +4624,7 @@ int qemuProcessStart(virConnectPtr conn, */ if (virDomainDefNeedsPlacementAdvice(vm->def)) { nodeset = virNumaGetAutoPlacementAdvice(vm->def->vcpus, - vm->def->mem.max_balloon); + virDomainDefGetMemoryCurrent(vm->def)); if (!nodeset) goto cleanup;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c index a386270..3aa6a5e 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -2149,7 +2149,7 @@ static int testDomainGetInfo(virDomainPtr domain,
info->state = virDomainObjGetState(privdom, NULL); info->memory = privdom->def->mem.cur_balloon; - info->maxMem = privdom->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(privdom->def); info->nrVirtCpu = privdom->def->vcpus; info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); ret = 0; @@ -2517,7 +2517,7 @@ testDomainGetMaxMemory(virDomainPtr domain) goto cleanup; }
- ret = privdom->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(privdom->def);
cleanup: if (privdom) @@ -2543,7 +2543,7 @@ static int testDomainSetMaxMemory(virDomainPtr domain, }
/* XXX validate not over host memory wrt to other domains */ - privdom->def->mem.max_balloon = memory; + virDomainDefSetMemoryInitial(privdom->def, memory); ret = 0;
cleanup: @@ -2569,7 +2569,7 @@ static int testDomainSetMemory(virDomainPtr domain, goto cleanup; }
- if (memory > privdom->def->mem.max_balloon) { + if (memory > virDomainDefGetMemoryCurrent(privdom->def)) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 68efd18..59ff33c 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1802,7 +1802,7 @@ umlDomainGetMaxMemory(virDomainPtr dom) if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0) goto cleanup;
- ret = vm->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(vm->def);
cleanup: if (vm) @@ -1838,7 +1838,7 @@ static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) goto cleanup; }
- vm->def->mem.max_balloon = newmax; + virDomainDefSetMemoryInitial(vm->def, newmax); ret = 0;
cleanup: @@ -1875,7 +1875,7 @@ static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) goto cleanup; }
- if (newmem > vm->def->mem.max_balloon) { + if (newmem > virDomainDefGetMemoryCurrent(vm->def)) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set memory higher than max memory")); goto cleanup; @@ -1922,7 +1922,7 @@ static int umlDomainGetInfo(virDomainPtr dom, } }
- info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index 55d3624..6697ecc 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -3894,7 +3894,7 @@ static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) * reading and while dumping xml */ /* def->mem.max_balloon = maxMemorySize * 1024; */ - def->mem.max_balloon = memorySize * 1024; + virDomainDefSetMemoryInitial(def, memorySize * 1024);
gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount); def->maxvcpus = def->vcpus = CPUCount; @@ -6055,7 +6055,7 @@ static char *vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, * the notation here seems to be inconsistent while * reading and while dumping xml */ - def->dom->mem.max_balloon = memorySize * 1024; + virDomainDefSetMemoryInitial(def->dom, memorySize * 1024); if (VIR_STRDUP(def->dom->os.type, "hvm") < 0) goto cleanup; def->dom->os.arch = virArchFromHost(); diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index fb7fa5b..71589a6 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -1126,7 +1126,7 @@ vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
info->state = virDomainObjGetState(vm, NULL); info->cpuTime = 0; - info->maxMem = vm->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(vm->def); info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index ac2542a..eba1a68 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -1375,7 +1375,7 @@ virVMXParseConfig(virVMXContext *ctx, goto cleanup; }
- def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */ + virDomainDefSetMemoryInitial(def, memsize * 1024); /* Scale from megabytes to kilobytes */
/* vmx:sched.mem.max -> def:mem.cur_balloon */ if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize, @@ -1388,8 +1388,8 @@ virVMXParseConfig(virVMXContext *ctx,
def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */
- if (def->mem.cur_balloon > def->mem.max_balloon) - def->mem.cur_balloon = def->mem.max_balloon; + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def);
/* vmx:sched.mem.minsize -> def:mem.min_guarantee */ if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0, @@ -1402,8 +1402,8 @@ virVMXParseConfig(virVMXContext *ctx,
def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */
- if (def->mem.min_guarantee > def->mem.max_balloon) - def->mem.min_guarantee = def->mem.max_balloon; + if (def->mem.min_guarantee > virDomainDefGetMemoryCurrent(def)) + def->mem.min_guarantee = virDomainDefGetMemoryCurrent(def);
/* vmx:numvcpus -> def:vcpus */ if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) @@ -3083,7 +3083,7 @@ virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virDomainDe
/* def:mem.max_balloon -> vmx:memsize */ /* max-memory must be a multiple of 4096 kilobyte */ - max_balloon = VIR_DIV_UP(def->mem.max_balloon, 4096) * 4096; + max_balloon = VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 4096) * 4096;
virBufferAsprintf(&buffer, "memsize = \"%llu\"\n", max_balloon / 1024); /* Scale from kilobytes to megabytes */ diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 354ab3f..ab9e6a6 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -479,7 +479,7 @@ xenXMDomainGetInfo(virConnectPtr conn, goto error;
memset(info, 0, sizeof(virDomainInfo)); - info->maxMem = entry->def->mem.max_balloon; + info->maxMem = virDomainDefGetMemoryCurrent(entry->def); info->memory = entry->def->mem.cur_balloon; info->nrVirtCpu = entry->def->vcpus; info->state = VIR_DOMAIN_SHUTOFF; @@ -557,8 +557,8 @@ xenXMDomainSetMemory(virConnectPtr conn, goto cleanup;
entry->def->mem.cur_balloon = memory; - if (entry->def->mem.cur_balloon > entry->def->mem.max_balloon) - entry->def->mem.cur_balloon = entry->def->mem.max_balloon; + if (entry->def->mem.cur_balloon > virDomainDefGetMemoryCurrent(entry->def)) + entry->def->mem.cur_balloon = virDomainDefGetMemoryCurrent(entry->def);
/* If this fails, should we try to undo our changes to the * in-memory representation of the config file. I say not! @@ -600,10 +600,10 @@ xenXMDomainSetMaxMemory(virConnectPtr conn, if (!(entry = virHashLookup(priv->configCache, filename))) goto cleanup;
- entry->def->mem.max_balloon = memory; - if (entry->def->mem.cur_balloon > entry->def->mem.max_balloon) - entry->def->mem.cur_balloon = entry->def->mem.max_balloon; + if (entry->def->mem.cur_balloon > memory) + entry->def->mem.cur_balloon = memory;
+ virDomainDefSetMemoryInitial(entry->def, memory); /* If this fails, should we try to undo our changes to the * in-memory representation of the config file. I say not! */ @@ -636,7 +636,7 @@ xenXMDomainGetMaxMemory(virConnectPtr conn, if (!(entry = virHashLookup(priv->configCache, filename))) goto cleanup;
- ret = entry->def->mem.max_balloon; + ret = virDomainDefGetMemoryCurrent(entry->def);
cleanup: xenUnifiedUnlock(priv); diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index afb6d6c..b3dd852 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1490,7 +1490,7 @@ xenapiDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) VIR_FREE(val); } memory = xenapiDomainGetMaxMemory(dom); - defPtr->mem.max_balloon = memory; + virDomainDefSetMemoryInitial(defPtr, memory); if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { defPtr->mem.cur_balloon = (unsigned long) (dynamic_mem / 1024); } else { diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 91bc649..35f0f04 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -495,8 +495,8 @@ createVMRecordFromXml(virConnectPtr conn, virDomainDefPtr def,
if (def->mem.cur_balloon) (*record)->memory_static_max = (int64_t) (def->mem.cur_balloon * 1024); - if (def->mem.max_balloon) - (*record)->memory_dynamic_max = (int64_t) (def->mem.max_balloon * 1024); + if (virDomainDefGetMemoryCurrent(def)) + (*record)->memory_dynamic_max = (int64_t) (virDomainDefGetMemoryCurrent(def) * 1024); else (*record)->memory_dynamic_max = (*record)->memory_static_max;
diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c index a2a1474..924f0d6 100644 --- a/src/xenconfig/xen_common.c +++ b/src/xenconfig/xen_common.c @@ -305,16 +305,18 @@ xenConfigSetString(virConfPtr conf, const char *setting, const char *str) static int xenParseMem(virConfPtr conf, virDomainDefPtr def) { + unsigned long long memory; + if (xenConfigGetULongLong(conf, "memory", &def->mem.cur_balloon, MIN_XEN_GUEST_SIZE * 2) < 0) return -1;
- if (xenConfigGetULongLong(conf, "maxmem", &def->mem.max_balloon, + if (xenConfigGetULongLong(conf, "maxmem", &memory, def->mem.cur_balloon) < 0) return -1;
def->mem.cur_balloon *= 1024; - def->mem.max_balloon *= 1024; + virDomainDefSetMemoryInitial(def, memory * 1024);
return 0; } @@ -1410,7 +1412,7 @@ static int xenFormatMem(virConfPtr conf, virDomainDefPtr def) { if (xenConfigSetInt(conf, "maxmem", - VIR_DIV_UP(def->mem.max_balloon, 1024)) < 0) + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 1024)) < 0) return -1;
if (xenConfigSetInt(conf, "memory", diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c index 3e18a7e..fbebf51 100644 --- a/src/xenconfig/xen_sxpr.c +++ b/src/xenconfig/xen_sxpr.c @@ -1155,10 +1155,11 @@ xenParseSxpr(const struct sexpr *root, } }
- def->mem.max_balloon = (sexpr_u64(root, "domain/maxmem") << 10); + virDomainDefSetMemoryInitial(def, (sexpr_u64(root, "domain/maxmem") << 10)); def->mem.cur_balloon = (sexpr_u64(root, "domain/memory") << 10); - if (def->mem.cur_balloon > def->mem.max_balloon) - def->mem.cur_balloon = def->mem.max_balloon; + + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def);
if (cpus != NULL) { if (virBitmapParse(cpus, 0, &def->cpumask, @@ -2213,7 +2214,7 @@ xenFormatSxpr(virConnectPtr conn, virBufferEscapeSexpr(&buf, "(name '%s')", def->name); virBufferAsprintf(&buf, "(memory %llu)(maxmem %llu)", VIR_DIV_UP(def->mem.cur_balloon, 1024), - VIR_DIV_UP(def->mem.max_balloon, 1024)); + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 1024)); virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus); /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is either 32, or 64 on a platform where long is big enough. */

On Fri, Feb 20, 2015 at 10:15:00 -0500, John Ferlan wrote:
On 02/18/2015 09:16 AM, Peter Krempa wrote:
As there are two possible approaches to define a domain's memory size - one used with legacy, non-NUMA VMs configured in the <memory> element and per-node based approach on NUMA machines - the user needs to make sure that both are specified correctly in the NUMA case.
To avoid this burden on the user I'd like to replace the NUMA case with automatic totaling of the memory size. To achieve this I need to replace direct access to the virDomainMemtune's 'max_balloon' field with two separate getters depending on the desired size.
The two sizes are needed as: 1) Startup memory size doesn't include memory modules in some hypervisors. 2) After startup these count as the usable memory size.
Note that the comments for the functions are future aware and document state that will be present after a few later patches. --- src/conf/domain_conf.c | 66 ++++++++++++++++++++++++++++++++++------ src/conf/domain_conf.h | 4 +++ src/hyperv/hyperv_driver.c | 2 +- src/libvirt_private.syms | 3 ++ src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 8 ++--- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_driver.c | 10 +++--- src/lxc/lxc_fuse.c | 4 +-- src/lxc/lxc_native.c | 4 +-- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_sdk.c | 12 ++++---- src/phyp/phyp_driver.c | 11 ++++--- src/qemu/qemu_command.c | 18 +++++++---- src/qemu/qemu_driver.c | 19 ++++++------ src/qemu/qemu_hotplug.c | 8 +++-- src/qemu/qemu_process.c | 2 +- src/test/test_driver.c | 8 ++--- src/uml/uml_driver.c | 8 ++--- src/vbox/vbox_common.c | 4 +-- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 12 ++++---- src/xen/xm_internal.c | 14 ++++----- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 4 +-- src/xenconfig/xen_common.c | 8 +++-- src/xenconfig/xen_sxpr.c | 9 +++--- 28 files changed, 160 insertions(+), 90 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6ef499d..e95851a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3172,24 +3172,26 @@ virDomainDefPostParseInternal(virDomainDefPtr def, return -1; }
- if (def->mem.cur_balloon > def->mem.max_balloon) { + if (def->mem.cur_balloon > virDomainDefGetMemoryCurrent(def)) { /* Older libvirt could get into this situation due to * rounding; if the discrepancy is less than 4MiB, we silently * round down, otherwise we flag the issue. */ if (VIR_DIV_UP(def->mem.cur_balloon, 4096) > - VIR_DIV_UP(def->mem.max_balloon, 4096)) { + VIR_DIV_UP(virDomainDefGetMemoryCurrent(def), 4096)) { virReportError(VIR_ERR_XML_ERROR, _("current memory '%lluk' exceeds " "maximum '%lluk'"), - def->mem.cur_balloon, def->mem.max_balloon); + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def)); return -1; } 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; + def->mem.cur_balloon, + virDomainDefGetMemoryCurrent(def)); + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); } } else if (def->mem.cur_balloon == 0) { - def->mem.cur_balloon = def->mem.max_balloon; + def->mem.cur_balloon = virDomainDefGetMemoryCurrent(def); }
/* @@ -6882,6 +6884,51 @@ virDomainParseMemory(const char *xpath, }
+/** + * virDomainDefGetMemoryInitial: + * @def: domain definition + * + * Returns the size of the initial amount of guest memory. The initial amount + * is the memory size is either the configured amount in the <memory> element + * or the sum of memory sizes of NUMA nodes in case NUMA is enabled in @def. + */ +unsigned long long +virDomainDefGetMemoryInitial(virDomainDefPtr def) +{ + return def->mem.max_balloon; +} + + +/** + * virDomainDefSetMemoryInitial: + * @def: domain definition + * @size: size to set + * + * Sets the initial memory size in @def. + */ +void +virDomainDefSetMemoryInitial(virDomainDefPtr def, + unsigned long long size) +{ + def->mem.max_balloon = size; +}
Odd concept - changing Initial memory, but I don't have a better name in mind...
+ + +/** + * virDomainDefGetMemoryCurrent: + * @def: domain definition + * + * Returns the current maximum memory size usable by the domain described by + * @def. This size is a sum of size returned by virDomainDefGetMemoryInitial + * and possible additional memory devices. + */ +unsigned long long +virDomainDefGetMemoryCurrent(virDomainDefPtr def) +{ + return virDomainDefGetMemoryInitial(def); +}
Ok - so part of me expect this one to return mem.cur_balloon - perhaps a name change to GetMemoryUsable would help?
I'll try using GetMemoryAvailable for the next version.
and of course begs the question why not bite the bullet and return mem.cur_balloon in a GetMemoryCurrent accessor...
I didn't need it currently. I'll look into it separately if I find it necessary.
+ + static int virDomainControllerModelTypeFromString(const virDomainControllerDef *def, const char *model) @@ -15956,10 +16003,11 @@ virDomainDefCheckABIStability(virDomainDefPtr src, goto error; }
- if (src->mem.max_balloon != dst->mem.max_balloon) { + if (virDomainDefGetMemoryInitial(src) != virDomainDefGetMemoryInitial(dst)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Target domain max memory %lld does not match source %lld"), - dst->mem.max_balloon, src->mem.max_balloon); + virDomainDefGetMemoryInitial(dst), + virDomainDefGetMemoryInitial(src)); goto error; }
Since the "future" (I assume) is that MemoryCurrent will include the hot (un)plug memory - does it make sense to also compare src/dst MemoryCurrent values even though for now it's essentially the same value? Although I believe that gets done in your later series and it's hard to keep them in my memory.
The memory modules will be compared individually so it doesn't matter much.
Of the remaining uses of GetInitial and {Get|Set}Current the ones I was wondering about are:
virLXCCgroupSetupMemTune libxlMakeDomBuildInfo phypBuildLpar
Wouldn't they be the corollary to qemuBuildCommandLine w/r/t using Initial instead of Current in order to define the memory for the guest as it starts up?
They are. I'll change them to use the Current/Available accessor although it won't make a difference for now as memory hotplug is explicitly forbidden for drivers other than qemu.
John
Peter

The memory sizes in qemu are aligned up to 1 MiB boundaries. There are two places where this was done once for the total size and then for individual NUMA cell sizes. Add a function that will align the sizes in one place so that it's clear where the sizes are aligned. --- src/qemu/qemu_command.c | 7 +++---- src/qemu/qemu_domain.c | 21 +++++++++++++++++++++ src/qemu/qemu_domain.h | 2 ++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index bf47702..7b83f9f 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7177,9 +7177,6 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, /* using of -numa memdev= cannot be combined with -numa mem=, thus we * need to check which approach to use */ for (i = 0; i < ncells; i++) { - unsigned long long cellmem = virDomainNumaGetNodeMemorySize(def->numa, i); - virDomainNumaSetNodeMemorySize(def->numa, i, VIR_ROUND_UP(cellmem, 1024)); - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) || virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) { if ((rc = qemuBuildMemoryCellBackendStr(def, qemuCaps, cfg, i, @@ -8313,13 +8310,15 @@ qemuBuildCommandLine(virConnectPtr conn, if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0) goto error; + if (qemuDomainAlignMemorySizes(def) < 0) + goto error; + /* 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. Update the * XML to reflect our rounding. */ virCommandAddArg(cmd, "-m"); - virDomainDefSetMemoryInitial(def, VIR_ROUND_UP(virDomainDefGetMemoryInitial(def), 1024)); virCommandAddArgFormat(cmd, "%llu", virDomainDefGetMemoryInitial(def) / 1024); if (def->mem.nhugepages && !virDomainNumaGetNodeCount(def->numa)) { diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 99c46d4..c41b3d3 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2832,3 +2832,24 @@ qemuDomObjEndAPI(virDomainObjPtr *vm) virObjectUnref(*vm); *vm = NULL; } + + +int +qemuDomainAlignMemorySizes(virDomainDefPtr def) +{ + unsigned long long mem; + size_t ncells = virDomainNumaGetNodeCount(def->numa); + size_t i; + + /* align NUMA cell sizes if relevant */ + for (i = 0; i < ncells; i++) { + mem = virDomainNumaGetNodeMemorySize(def->numa, i); + virDomainNumaSetNodeMemorySize(def->numa, i, VIR_ROUND_UP(mem, 1024)); + } + + /* align initial memory size */ + mem = virDomainDefGetMemoryInitial(def); + virDomainDefSetMemoryInitial(def, VIR_ROUND_UP(mem, 1024)); + + return 0; +} diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index b2c3881..faf4ee2 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -414,4 +414,6 @@ int qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo, void qemuDomObjEndAPI(virDomainObjPtr *vm); +int qemuDomainAlignMemorySizes(virDomainDefPtr def); + #endif /* __QEMU_DOMAIN_H__ */ -- 2.2.2

On 02/18/2015 09:16 AM, Peter Krempa wrote:
The memory sizes in qemu are aligned up to 1 MiB boundaries. There are two places where this was done once for the total size and then for individual NUMA cell sizes.
Add a function that will align the sizes in one place so that it's clear where the sizes are aligned. --- src/qemu/qemu_command.c | 7 +++---- src/qemu/qemu_domain.c | 21 +++++++++++++++++++++ src/qemu/qemu_domain.h | 2 ++ 3 files changed, 26 insertions(+), 4 deletions(-)
ACK John

The total NUMA memory consists of the sum of individual NUMA node memory amounts. --- src/conf/numa_conf.c | 13 +++++++++++++ src/conf/numa_conf.h | 1 + src/libvirt_private.syms | 1 + 3 files changed, 15 insertions(+) diff --git a/src/conf/numa_conf.c b/src/conf/numa_conf.c index fb9884a..a3e8ab2 100644 --- a/src/conf/numa_conf.c +++ b/src/conf/numa_conf.c @@ -892,3 +892,16 @@ virDomainNumaSetNodeMemorySize(virDomainNumaPtr numa, { numa->mem_nodes[node].mem = size; } + + +unsigned long long +virDomainNumaGetMemorySize(virDomainNumaPtr numa) +{ + size_t i; + unsigned long long ret = 0; + + for (i = 0; i < numa->nmem_nodes; i++) + ret += numa->mem_nodes[i].mem; + + return ret; +} diff --git a/src/conf/numa_conf.h b/src/conf/numa_conf.h index e0cc62d..184d045 100644 --- a/src/conf/numa_conf.h +++ b/src/conf/numa_conf.h @@ -91,6 +91,7 @@ virNumaMemAccess virDomainNumaGetNodeMemoryAccessMode(virDomainNumaPtr numa, size_t node); unsigned long long virDomainNumaGetNodeMemorySize(virDomainNumaPtr numa, size_t node); +unsigned long long virDomainNumaGetMemorySize(virDomainNumaPtr numa); /* diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a58b2b9..e2eb40c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -633,6 +633,7 @@ virNodeDeviceObjUnlock; virDomainNumaCheckABIStability; virDomainNumaEquals; virDomainNumaFree; +virDomainNumaGetMemorySize; virDomainNumaGetNodeCount; virDomainNumaGetNodeCpumask; virDomainNumaGetNodeMemoryAccessMode; -- 2.2.2

On 02/18/2015 09:16 AM, Peter Krempa wrote:
The total NUMA memory consists of the sum of individual NUMA node memory amounts. --- src/conf/numa_conf.c | 13 +++++++++++++ src/conf/numa_conf.h | 1 + src/libvirt_private.syms | 1 + 3 files changed, 15 insertions(+)
ACK - John

Use the NUMA total instead of the configured size both in XML and for uses in the code once NUMA is enabled for a domain. One test case change is necessary as the rounding of the individual cell sizes was not matching the rounding of the total size. --- src/conf/domain_conf.c | 6 ++++++ tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e95851a..a4cb930 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -6895,6 +6895,12 @@ virDomainParseMemory(const char *xpath, unsigned long long virDomainDefGetMemoryInitial(virDomainDefPtr def) { + unsigned long long ret; + + /* return NUMA memory size total in case numa is enabled */ + if ((ret = virDomainNumaGetMemorySize(def->numa)) > 0) + return ret; + return def->mem.max_balloon; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args index 513d657..5dd7fcd 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args @@ -1,5 +1,5 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ -/usr/bin/kvm -S -M pc -m 24104 -smp 32 \ +/usr/bin/kvm -S -M pc -m 24105 -smp 32 \ -object memory-backend-ram,id=ram-node0,size=20971520,host-nodes=3,\ policy=preferred \ -numa node,nodeid=0,cpus=0,memdev=ram-node0 \ -- 2.2.2

On 02/18/2015 09:16 AM, Peter Krempa wrote:
Use the NUMA total instead of the configured size both in XML and for uses in the code once NUMA is enabled for a domain.
One test case change is necessary as the rounding of the individual cell sizes was not matching the rounding of the total size. --- src/conf/domain_conf.c | 6 ++++++ tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-)
ACK - John
participants (2)
-
John Ferlan
-
Peter Krempa