[libvirt] [PATCHv2 14/15] virsh: improve storage unit parsing

Eric Blake eblake at redhat.com
Tue Mar 6 00:34:29 UTC 2012


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




More information about the libvir-list mailing list