Now can now do:
virsh vol-resize $vol 10M
virsh blockresize $dom $vol 10M
to get both interfaces to resize to 10MiB. The remaining wart
is that vol-resize defaults to bytes, but blockresize defaults
to KiB, but we can't break existing scripts; oh well, it's no
worse than the same wart of the underlying virDomainBlockResize.
* tools/virsh.c (vshCommandOptScaledInt): New function.
(cmdVolResize): Don't pass negative size.
(cmdVolSize): Use new helper routine.
(cmdBlockResize): Likewise; also support bytes.
* tools/virsh.pod (NOTES): Document suffixes.
(blockresize, vol-create-as, vol-resize): Point to notes.
---
v2: new
tools/virsh.c | 113 +++++++++++++++++++++++++++++++------------------------
tools/virsh.pod | 43 ++++++++++++++++----
2 files changed, 98 insertions(+), 58 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 4361a6b..d5cc46b 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -313,6 +313,10 @@ static int vshCommandOptLongLong(const vshCmd *cmd, const char
*name,
static int vshCommandOptULongLong(const vshCmd *cmd, const char *name,
unsigned long long *value)
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
+static int vshCommandOptScaledInt(const vshCmd *cmd, const char *name,
+ unsigned long long *value, int scale,
+ unsigned long long max)
+ ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
static const vshCmdOpt *vshCommandOptArgv(const vshCmd *cmd,
const vshCmdOpt *opt);
@@ -7471,9 +7475,10 @@ static const vshCmdInfo info_block_resize[] = {
static const vshCmdOptDef opts_block_resize[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"path", VSH_OT_DATA, VSH_OFLAG_REQ, N_("Fully-qualified path of block
device")},
- {"size", VSH_OT_INT, VSH_OFLAG_REQ, N_("New size of the block device
in kilobytes, "
- "the size must be integer")},
+ {"path", VSH_OT_DATA, VSH_OFLAG_REQ,
+ N_("Fully-qualified path of block device")},
+ {"size", VSH_OT_INT, VSH_OFLAG_REQ,
+ N_("New size of the block device, as scaled integer (default KiB)")},
{NULL, 0, 0, NULL}
};
@@ -7494,15 +7499,16 @@ cmdBlockResize(vshControl *ctl, const vshCmd *cmd)
return false;
}
- if (vshCommandOptULongLong(cmd, "size", &size) < 0) {
+ if (vshCommandOptScaledInt(cmd, "size", &size, 1024, ULLONG_MAX) <
0) {
vshError(ctl, "%s", _("Unable to parse integer"));
return false;
}
- if (size > ULLONG_MAX / 1024) {
- vshError(ctl, _("Size must be less than %llu"), ULLONG_MAX / 1024);
- return false;
- }
+ /* Prefer the older interface of KiB. */
+ if (size % 1024 == 0)
+ size /= 1024;
+ else
+ flags |= VIR_DOMAIN_BLOCK_RESIZE_BYTES;
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false;
@@ -10892,43 +10898,26 @@ static const vshCmdInfo info_vol_create_as[] = {
static const vshCmdOptDef opts_vol_create_as[] = {
{"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
{"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")},
- {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, N_("size of the vol with
optional k,M,G,T suffix")},
- {"allocation", VSH_OT_STRING, 0, N_("initial allocation size with
optional k,M,G,T suffix")},
- {"format", VSH_OT_STRING, 0, N_("file format type
raw,bochs,qcow,qcow2,vmdk")},
- {"backing-vol", VSH_OT_STRING, 0, N_("the backing volume if taking a
snapshot")},
- {"backing-vol-format", VSH_OT_STRING, 0, N_("format of backing volume
if taking a snapshot")},
+ {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ,
+ N_("size of the vol, as scaled integer (default bytes)")},
+ {"allocation", VSH_OT_STRING, 0,
+ N_("initial allocation size, as scaled integer (default bytes)")},
+ {"format", VSH_OT_STRING, 0,
+ N_("file format type raw,bochs,qcow,qcow2,vmdk")},
+ {"backing-vol", VSH_OT_STRING, 0,
+ N_("the backing volume if taking a snapshot")},
+ {"backing-vol-format", VSH_OT_STRING, 0,
+ N_("format of backing volume if taking a snapshot")},
{NULL, 0, 0, NULL}
};
-static int cmdVolSize(const char *data, unsigned long long *val)
+static int
+cmdVolSize(const char *data, unsigned long long *val)
{
char *end;
if (virStrToLong_ull(data, &end, 10, val) < 0)
return -1;
-
- if (end && *end) {
- /* Deliberate fallthrough cases here :-) */
- switch (*end) {
- case 'T':
- *val *= 1024;
- /* fallthrough */
- case 'G':
- *val *= 1024;
- /* fallthrough */
- case 'M':
- *val *= 1024;
- /* fallthrough */
- case 'k':
- *val *= 1024;
- break;
- default:
- return -1;
- }
- end++;
- if (*end)
- return -1;
- }
- return 0;
+ return virScaleInteger(val, end, 1, ULLONG_MAX);
}
static bool
@@ -11754,7 +11743,7 @@ static const vshCmdInfo info_vol_resize[] = {
static const vshCmdOptDef opts_vol_resize[] = {
{"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or
path")},
{"capacity", VSH_OT_DATA, VSH_OFLAG_REQ,
- N_("new capacity for the vol with optional k,M,G,T suffix")},
+ N_("new capacity for the vol, as scaled integer (default bytes)")},
{"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
{"allocate", VSH_OT_BOOL, 0,
N_("allocate the new capacity, rather than leaving it sparse")},
@@ -11792,16 +11781,12 @@ cmdVolResize(vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0)
goto cleanup;
if (delta && *capacityStr == '-') {
- if (cmdVolSize(capacityStr + 1, &capacity) < 0) {
- vshError(ctl, _("Malformed size %s"), capacityStr);
- goto cleanup;
- }
- capacity = -capacity;
- } else {
- if (cmdVolSize(capacityStr, &capacity) < 0) {
- vshError(ctl, _("Malformed size %s"), capacityStr);
- goto cleanup;
- }
+ capacityStr++;
+ flags |= VIR_STORAGE_VOL_RESIZE_SHRINK;
+ }
+ if (cmdVolSize(capacityStr, &capacity) < 0) {
+ vshError(ctl, _("Malformed size %s"), capacityStr);
+ goto cleanup;
}
if (virStorageVolResize(vol, capacity, flags) == 0) {
@@ -17851,6 +17836,36 @@ vshCommandOptULongLong(const vshCmd *cmd, const char *name,
/**
+ * vshCommandOptScaledInt:
+ * @cmd command reference
+ * @name option name
+ * @value result
+ * @scale default of 1 or 1024, if no suffix is present
+ * @max maximum value permitted
+ *
+ * Returns option as long long, scaled according to suffix
+ * See vshCommandOptInt()
+ */
+static int
+vshCommandOptScaledInt(const vshCmd *cmd, const char *name,
+ unsigned long long *value, int scale,
+ unsigned long long max)
+{
+ const char *str;
+ int ret;
+ char *end;
+
+ ret = vshCommandOptString(cmd, name, &str);
+ if (ret <= 0)
+ return ret;
+ if (virStrToLong_ull(str, &end, 10, value) < 0 ||
+ virScaleInteger(value, end, scale, max) < 0)
+ return -1;
+ return 1;
+}
+
+
+/**
* vshCommandOptBool:
* @cmd command reference
* @name option name
diff --git a/tools/virsh.pod b/tools/virsh.pod
index b365624..74d3ff5 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -115,6 +115,25 @@ program returned, may not mean the action is complete and you
must poll periodically to detect that the guest completed the
operation.
+Several B<virsh> commands take an optionally scaled integer; if no
+scale is provided, then the default is listed in the command (for
+historical reasons, some commands default to bytes, while other
+commands default to kibibytes). The following case-insensitive
+suffixes can be used to select a specfic scale:
+ b, byte byte 1
+ KB kilobyte 1,000
+ k, KiB kibibyte 1,024
+ MB megabyte 1,000,000
+ M, MiB mebibyte 1,048,576
+ GB gigabyte 1,000,000,000
+ G, GiB gibibyte 1,073,741,824
+ TB terabyte 1,000,000,000,000
+ T, TiB tebibyte 1,099,511,627,776
+ PB petabyte 1,000,000,000,000,000
+ P, PiB pebibyte 1,125,899,906,842,624
+ EB exabyte 1,000,000,000,000,000,000
+ E, EiB exbibyte 1,152,921,504,606,846,976
+
=head1 GENERIC COMMANDS
The following commands are generic i.e. not specific to a domain.
@@ -654,11 +673,14 @@ If I<--info> is specified, the active job information on the
specified
disk will be printed.
I<bandwidth> can be used to set bandwidth limit for the active job.
-=item B<blockresize> I<domain> I<--path> I<--size>
+=item B<blockresize> I<domain> I<path> I<size>
-Resize a block device of domain while the domain is running, I<--path>
-specifies the absolute path of the block device, I<--size> specifies the
-new size in kilobytes
+Resize a block device of domain while the domain is running, I<path>
+specifies the absolute path of the block device, I<size> is a scaled
+integer (see B<NOTES> above) which defaults to KiB (1024) if there
+is no suffix. You must use a suffix of "B" to get bytes (note that
+for historical reasons, this differs from B<vol-resize> which defaults
+to bytes without a suffix).
=item B<dominfo> I<domain-id>
@@ -2007,10 +2029,10 @@ Create a volume from a set of arguments.
I<pool-or-uuid> is the name or UUID of the storage pool to create the volume
in.
I<name> is the name of the new volume.
-I<capacity> is the size of the volume to be created, with optional k, M, G, or
-T suffix.
-I<--allocation> I<size> is the initial size to be allocated in the volume,
with
-optional k, M, G, or T suffix.
+I<capacity> is the size of the volume to be created, as a scaled integer
+(see B<NOTES> above), defaulting to bytes if there is no suffix.
+I<--allocation> I<size> is the initial size to be allocated in the volume,
+also as a scaled integer defaulting to bytes.
I<--format> I<string> is used in file based storage pools to specify the
volume
file format to use; raw, bochs, qcow, qcow2, vmdk.
I<--backing-vol> I<vol-name-or-key-or-path> is the source backing
@@ -2146,7 +2168,10 @@ is in. I<vol-name-or-key-or-path> is the name or key or path
of the volume
to resize. The new capacity might be sparse unless I<--allocate> is
specified. Normally, I<capacity> is the new size, but if I<--delta>
is present, then it is added to the existing size. Attempts to shrink
-the volume will fail unless I<--shrink> is present.
+the volume will fail unless I<--shrink> is present. <capacity> is a
+scaled integer (see B<NOTES> above), which defaults to bytes if there
+is no suffix. This command is only safe for storage volumes not in
+use by an active guest; see also B<blockresize> for live resizing.
=back
--
1.7.7.6