The last vestige of the inaccurate 'kilobytes' when we meant 1024 is
now gone. And virsh is now useful for setting memory in units other
than KiB.
* tools/virsh.c (cmdSetmem, cmdSetmaxmem): Use new helper routine,
allow passing bogus arguments on to hypervisor to test driver
sanity checking, and fix leak on parse error.
(cmdMemtuneGetSize): New helper.
(cmdMemtune): Use it.
* tools/virsh.pod (setmem, setmaxmem, memtune): Document this.
---
v2: new
tools/virsh.c | 110 +++++++++++++++++++++++++++++++++----------------------
tools/virsh.pod | 48 ++++++++++++------------
2 files changed, 90 insertions(+), 68 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index d5cc46b..b93706f 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -5668,7 +5668,7 @@ cleanup:
}
/*
- * "setmemory" command
+ * "setmem" command
*/
static const vshCmdInfo info_setmem[] = {
{"help", N_("change memory allocation")},
@@ -5678,7 +5678,9 @@ static const vshCmdInfo info_setmem[] = {
static const vshCmdOptDef opts_setmem[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of kilobytes of
memory")},
+ {"kilobytes", VSH_OT_ALIAS, 0, "size"},
+ {"size", VSH_OT_INT, VSH_OFLAG_REQ,
+ N_("new memory size, as scaled integer (default KiB)")},
{"config", VSH_OT_BOOL, 0, N_("affect next boot")},
{"live", VSH_OT_BOOL, 0, N_("affect running domain")},
{"current", VSH_OT_BOOL, 0, N_("affect current domain")},
@@ -5689,8 +5691,9 @@ static bool
cmdSetmem(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom;
- virDomainInfo info;
- unsigned long kilobytes = 0;
+ unsigned long long bytes = 0;
+ unsigned long long max;
+ unsigned long kibibytes = 0;
bool ret = true;
int config = vshCommandOptBool(cmd, "config");
int live = vshCommandOptBool(cmd, "live");
@@ -5719,36 +5722,25 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false;
- if (vshCommandOptUL(cmd, "kilobytes", &kilobytes) < 0) {
+ /* The API expects 'unsigned long' KiB, so depending on whether we
+ * are 32-bit or 64-bit determines the maximum we can use. */
+ if (sizeof(kibibytes) < sizeof(max))
+ max = 1024ull * ULONG_MAX;
+ else
+ max = ULONG_MAX;
+ if (vshCommandOptScaledInt(cmd, "size", &bytes, 1024, max) < 0) {
vshError(ctl, "%s", _("memory size has to be a number"));
- return false;
- }
-
- if (kilobytes <= 0) {
- virDomainFree(dom);
- vshError(ctl, _("Invalid value of %lu for memory size"), kilobytes);
- return false;
- }
-
- if (virDomainGetInfo(dom, &info) != 0) {
virDomainFree(dom);
- vshError(ctl, "%s", _("Unable to verify MaxMemorySize"));
- return false;
- }
-
- if (kilobytes > info.maxMem) {
- virDomainFree(dom);
- vshError(ctl, _("Requested memory size %lu kb is larger than maximum of %lu
kb"),
- kilobytes, info.maxMem);
return false;
}
+ kibibytes = VIR_DIV_UP(bytes, 1024);
if (flags == -1) {
- if (virDomainSetMemory(dom, kilobytes) != 0) {
+ if (virDomainSetMemory(dom, kibibytes) != 0) {
ret = false;
}
} else {
- if (virDomainSetMemoryFlags(dom, kilobytes, flags) < 0) {
+ if (virDomainSetMemoryFlags(dom, kibibytes, flags) < 0) {
ret = false;
}
}
@@ -5768,7 +5760,9 @@ static const vshCmdInfo info_setmaxmem[] = {
static const vshCmdOptDef opts_setmaxmem[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum memory limit in
kilobytes")},
+ {"kilobytes", VSH_OT_ALIAS, 0, "size"},
+ {"size", VSH_OT_INT, VSH_OFLAG_REQ,
+ N_("new maximum memory size, as scaled integer (default KiB)")},
{"config", VSH_OT_BOOL, 0, N_("affect next boot")},
{"live", VSH_OT_BOOL, 0, N_("affect running domain")},
{"current", VSH_OT_BOOL, 0, N_("affect current domain")},
@@ -5779,7 +5773,9 @@ static bool
cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom;
- int kilobytes = 0;
+ unsigned long long bytes = 0;
+ unsigned long long max;
+ unsigned long kibibytes = 0;
bool ret = true;
int config = vshCommandOptBool(cmd, "config");
int live = vshCommandOptBool(cmd, "live");
@@ -5807,24 +5803,26 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false;
- if (vshCommandOptInt(cmd, "kilobytes", &kilobytes) < 0) {
+ /* The API expects 'unsigned long' KiB, so depending on whether we
+ * are 32-bit or 64-bit determines the maximum we can use. */
+ if (sizeof(kibibytes) < sizeof(max))
+ max = 1024ull * ULONG_MAX;
+ else
+ max = ULONG_MAX;
+ if (vshCommandOptScaledInt(cmd, "size", &bytes, 1024, max) < 0) {
vshError(ctl, "%s", _("memory size has to be a number"));
- return false;
- }
-
- if (kilobytes <= 0) {
virDomainFree(dom);
- vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
return false;
}
+ kibibytes = VIR_DIV_UP(bytes, 1024);
if (flags == -1) {
- if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
+ if (virDomainSetMaxMemory(dom, kibibytes) != 0) {
vshError(ctl, "%s", _("Unable to change
MaxMemorySize"));
ret = false;
}
} else {
- if (virDomainSetMemoryFlags(dom, kilobytes, flags) < 0) {
+ if (virDomainSetMemoryFlags(dom, kibibytes, flags) < 0) {
vshError(ctl, "%s", _("Unable to change
MaxMemorySize"));
ret = false;
}
@@ -5997,21 +5995,45 @@ static const vshCmdInfo info_memtune[] = {
static const vshCmdOptDef opts_memtune[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
{"hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
- N_("Max memory in kilobytes")},
+ N_("Max memory, as scaled integer (default KiB)")},
{"soft-limit", VSH_OT_INT, VSH_OFLAG_NONE,
- N_("Memory during contention in kilobytes")},
+ N_("Memory during contention, as scaled integer (default KiB)")},
{"swap-hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
- N_("Max memory plus swap in kilobytes")},
+ N_("Max memory plus swap, as scaled integer (default KiB)")},
{"min-guarantee", VSH_OT_INT, VSH_OFLAG_NONE,
- N_("Min guaranteed memory in kilobytes")},
+ N_("Min guaranteed memory, as scaled integer (default KiB)")},
{"config", VSH_OT_BOOL, 0, N_("affect next boot")},
{"live", VSH_OT_BOOL, 0, N_("affect running domain")},
{"current", VSH_OT_BOOL, 0, N_("affect current domain")},
{NULL, 0, 0, NULL}
};
+static int
+cmdMemtuneGetSize(const vshCmd *cmd, const char *name, long long *value)
+{
+ int ret;
+ unsigned long long tmp;
+ const char *str;
+ char *end;
+
+ ret = vshCommandOptString(cmd, name, &str);
+ if (ret <= 0)
+ return ret;
+ if (virStrToLong_ll(str, &end, 10, value) < 0)
+ return -1;
+ if (*value < 0) {
+ *value = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
+ return 1;
+ }
+ tmp = *value;
+ if (virScaleInteger(&tmp, end, 1024, LLONG_MAX) < 0)
+ return -1;
+ *value = VIR_DIV_UP(tmp, 1024);
+ return 0;
+}
+
static bool
-cmdMemtune(vshControl * ctl, const vshCmd * cmd)
+cmdMemtune(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom;
long long hard_limit = 0, soft_limit = 0, swap_hard_limit = 0;
@@ -6044,10 +6066,10 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false;
- if (vshCommandOptLongLong(cmd, "hard-limit", &hard_limit) < 0 ||
- vshCommandOptLongLong(cmd, "soft-limit", &soft_limit) < 0 ||
- vshCommandOptLongLong(cmd, "swap-hard-limit", &swap_hard_limit)
< 0 ||
- vshCommandOptLongLong(cmd, "min-guarantee", &min_guarantee) < 0)
{
+ if (cmdMemtuneGetSize(cmd, "hard-limit", &hard_limit) < 0 ||
+ cmdMemtuneGetSize(cmd, "soft-limit", &soft_limit) < 0 ||
+ cmdMemtuneGetSize(cmd, "swap-hard-limit", &swap_hard_limit) < 0
||
+ cmdMemtuneGetSize(cmd, "min-guarantee", &min_guarantee) < 0) {
vshError(ctl, "%s",
_("Unable to parse integer parameter"));
goto cleanup;
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 74d3ff5..a13a3b2 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1153,7 +1153,7 @@ B<Examples>
# send a tab, held for 1 second
virsh send-key --holdtime 1000 0xf
-=item B<setmem> I<domain-id> B<kilobytes> [[I<--config>]
[I<--live>] |
+=item B<setmem> I<domain-id> B<size> [[I<--config>]
[I<--live>] |
[I<--current>]]
Change the memory allocation for a guest domain.
@@ -1164,15 +1164,17 @@ Both I<--live> and I<--config> flags may be given, but
I<--current> is
exclusive. If no flag is specified, behavior is different depending
on hypervisor.
-Some hypervisors require a larger granularity than kilobytes, and requests
+I<size> is a scaled integer (see B<NOTES> above); it defaults to kibibytes
+(1024) unless you provide a suffix (and the older option name I<--kilobytes>
+is available as a deprecated synonym) . Libvirt rounds up to the nearest
+kibibyte. Some hypervisors require a larger granularity than KiB, and requests
that are not an even multiple will be rounded up. For example, vSphere/ESX
-rounds the parameter up unless the kB argument is evenly divisible by 1024
-(that is, the kB argument happens to represent megabytes).
+rounds the parameter up to mebibytes (1024 kibibytes).
For Xen, you can only adjust the memory of a running domain if the domain is
paravirtualized or running the PV balloon driver.
-=item B<setmaxmem> I<domain-id> B<kilobytes> [[I<--config>]
[I<--live>] |
+=item B<setmaxmem> I<domain-id> B<size> [[I<--config>]
[I<--live>] |
[I<--current>]]
Change the maximum memory allocation limit for a guest domain.
@@ -1185,22 +1187,24 @@ on hypervisor.
This command works for at least the Xen, QEMU/KVM and vSphere/ESX hypervisors.
-Some hypervisors require a larger granularity than kilobytes, rounding up
-requests that are not an even multiple of the desired amount. vSphere/ESX
-is one of these, requiring the parameter to be evenly divisible by 4MB. For
-vSphere/ESX, 263168 (257MB) would be rounded up because it's not a multiple
-of 4MB, while 266240 (260MB) is valid without rounding.
-
+I<size> is a scaled integer (see B<NOTES> above); it defaults to kibibytes
+(1024) unless you provide a suffix (and the older option name I<--kilobytes>
+is available as a deprecated synonym) . Libvirt rounds up to the nearest
+kibibyte. Some hypervisors require a larger granularity than KiB, and requests
+that are not an even multiple will be rounded up. For example, vSphere/ESX
+rounds the parameter up to mebibytes (1024 kibibytes).
-=item B<memtune> I<domain-id> [I<--hard-limit> B<kilobytes>]
-[I<--soft-limit> B<kilobytes>] [I<--swap-hard-limit>
B<kilobytes>]
-[I<--min-guarantee> B<kilobytes>] [[I<--config>] [I<--live>] |
[I<--current>]]
+=item B<memtune> I<domain-id> [I<--hard-limit> B<size>]
+[I<--soft-limit> B<size>] [I<--swap-hard-limit> B<size>]
+[I<--min-guarantee> B<size>] [[I<--config>] [I<--live>] |
[I<--current>]]
Allows you to display or set the domain memory parameters. Without
flags, the current settings are displayed; with a flag, the
appropriate limit is adjusted if supported by the hypervisor. LXC and
QEMU/KVM support I<--hard-limit>, I<--soft-limit>, and
I<--swap-hard-limit>.
-I<--min-guarantee> is supported only by ESX hypervisor.
+I<--min-guarantee> is supported only by ESX hypervisor. Each of these
+limits are scaled integers (see B<NOTES> above), with a default of
+kibibytes (blocks of 1024) if no suffix is present.
If I<--live> is specified, affect a running guest.
If I<--config> is specified, affect the next boot of a persistent guest.
@@ -1218,24 +1222,20 @@ one needs guess and try.
=item I<--hard-limit>
-The maximum memory the guest can use. The units for this value are kilobytes
-(i.e. blocks of 1024 bytes).
+The maximum memory the guest can use.
=item I<--soft-limit>
-The memory limit to enforce during memory contention. The units for this
-value are kilobytes (i.e. blocks of 1024 bytes).
+The memory limit to enforce during memory contention.
=item I<--swap-hard-limit>
-The maximum memory plus swap the guest can use. The units for this value are
-kilobytes (i.e. blocks of 1024 bytes). This has to be more than hard-limit
-value provided.
+The maximum memory plus swap the guest can use. This has to be more
+than hard-limit value provided.
=item I<--min-guarantee>
-The guaranteed minimum memory allocation for the guest. The units for this
-value are kilobytes (i.e. blocks of 1024 bytes).
+The guaranteed minimum memory allocation for the guest.
=back
--
1.7.7.6