From: "Zeeshan Ali (Khattak)" <zeeshanak@xxxxxxxxx> Add a new function to allow changing of capacity of storage volumes. Plan out several flags, even if not all of them will be implemented up front. Expose the new command via 'virsh vol-resize'. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- include/libvirt/libvirt.h.in | 11 ++++++ python/generator.py | 1 + src/driver.h | 5 +++ src/libvirt.c | 76 ++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + tools/virsh.c | 82 ++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 11 ++++++ 7 files changed, 187 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index e99cd00..d26cbbd 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2386,6 +2386,17 @@ char * virStorageVolGetXMLDesc (virStorageVolPtr pool, char * virStorageVolGetPath (virStorageVolPtr vol); +typedef enum { + VIR_STORAGE_VOL_RESIZE_ALLOCATE = 1 << 0, /* force allocation of new size */ + VIR_STORAGE_VOL_RESIZE_DELTA = 1 << 1, /* size is relative to current */ + VIR_STORAGE_VOL_RESIZE_SHRINK = 1 << 2, /* allow decrease in capacity */ +} virStorageVolResizeFlags; + +int virStorageVolResize (virStorageVolPtr vol, + long long capacity, + unsigned int flags); + + /** * virKeycodeSet: * diff --git a/python/generator.py b/python/generator.py index de635dc..791b267 100755 --- a/python/generator.py +++ b/python/generator.py @@ -259,6 +259,7 @@ py_types = { 'double': ('d', None, "double", "double"), 'unsigned int': ('i', None, "int", "int"), 'unsigned long': ('l', None, "long", "long"), + 'long long': ('l', None, "longlong", "long long"), 'unsigned long long': ('l', None, "longlong", "long long"), 'unsigned char *': ('z', None, "charPtr", "char *"), 'char *': ('z', None, "charPtr", "char *"), diff --git a/src/driver.h b/src/driver.h index df2aa60..485b578 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1261,6 +1261,10 @@ typedef int unsigned long long offset, unsigned long long length, unsigned int flags); +typedef int + (*virDrvStorageVolResize) (virStorageVolPtr vol, + long long capacity, + unsigned int flags); typedef int (*virDrvStoragePoolIsActive)(virStoragePoolPtr pool); @@ -1323,6 +1327,7 @@ struct _virStorageDriver { virDrvStorageVolGetInfo volGetInfo; virDrvStorageVolGetXMLDesc volGetXMLDesc; virDrvStorageVolGetPath volGetPath; + virDrvStorageVolResize volResize; virDrvStoragePoolIsActive poolIsActive; virDrvStoragePoolIsPersistent poolIsPersistent; }; diff --git a/src/libvirt.c b/src/libvirt.c index e9d638b..540d74a 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -12927,6 +12927,82 @@ error: return NULL; } +/** + * virStorageVolResize: + * @vol: pointer to storage volume + * @capacity: new capacity, in bytes + * @flags: bitwise-OR of virStorageVolResizeFlags + * + * Changes the capacity of the storage volume @vol to @capacity. The + * operation will fail if the new capacity requires allocation that would + * exceed the remaining free space in the parent pool. The contents of + * the new capacity will appear as all zero bytes. + * + * Normally, the operation will attempt to affect capacity with a minimum + * impact on allocation (that is, the default operation favors a sparse + * resize). If @flags contains VIR_STORAGE_VOL_RESIZE_ALLOCATE, then the + * operation will ensure that allocation is sufficient for the new + * capacity; this may make the operation take noticeably longer. + * + * Normally, the operation treats @capacity as the new size in bytes; + * but if @flags contains VIR_STORAGE_RESIZE_DELTA, then @capacity + * represents the size difference to add to the current size. It is + * up to the storage pool implementation whether unaligned requests are + * rounded up to the next valid boundary, or rejected. + * + * Normally, this operation should only be used to enlarge capacity; + * but if @flags contains VIR_STORAGE_RESIZE_SHRINK, it is possible to + * attempt a reduction in capacity even though it might cause data loss. + * + * Returns 0 on success, or -1 on error. + */ +int +virStorageVolResize(virStorageVolPtr vol, + long long capacity, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("vol=%p capacity=%lld flags=%x", vol, capacity, flags); + + virResetLastError(); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = vol->conn; + + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + /* Negative capacity is valid only with both delta and shrink; + * zero capacity is valid with either delta or shrink. */ + if ((capacity < 0 && !(flags & VIR_STORAGE_VOL_RESIZE_DELTA) && + !(flags & VIR_STORAGE_VOL_RESIZE_SHRINK)) || + (capacity == 0 && !((flags & VIR_STORAGE_VOL_RESIZE_DELTA) || + (flags & VIR_STORAGE_VOL_RESIZE_SHRINK)))) { + virLibStorageVolError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->storageDriver && conn->storageDriver->volResize) { + int ret; + ret = conn->storageDriver->volResize(vol, capacity, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(vol->conn); + return -1; +} /** * virNodeNumOfDevices: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 1340b0c..8bdb24b 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -519,6 +519,7 @@ LIBVIRT_0.9.9 { LIBVIRT_0.9.10 { global: virDomainShutdownFlags; + virStorageVolResize; virStorageVolWipePattern; } LIBVIRT_0.9.9; diff --git a/tools/virsh.c b/tools/virsh.c index 9b37dc0..ffcd746 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -11279,6 +11279,87 @@ cmdVolInfo(vshControl *ctl, const vshCmd *cmd) return ret; } +/* + * "vol-resize" command + */ +static const vshCmdInfo info_vol_resize[] = { + {"help", N_("resize a vol")}, + {"desc", N_("Resizes a storage volume.")}, + {NULL, NULL} +}; + +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")}, + {"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")}, + {"delta", VSH_OT_BOOL, 0, + N_("use capacity as a delta to current size, rather than the new size")}, + {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolResize(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + const char *capacityStr = NULL; + unsigned long long capacity = 0; + unsigned int flags = 0; + bool ret = false; + bool delta = false; + + if (vshCommandOptBool(cmd, "allocate")) + flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; + if (vshCommandOptBool(cmd, "delta")) { + delta = true; + flags |= VIR_STORAGE_VOL_RESIZE_DELTA; + } + if (vshCommandOptBool(cmd, "shrink")) + flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + 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; + } + } + + if (virStorageVolResize(vol, capacity, flags) == 0) { + vshPrint(ctl, + delta ? _("Size of volume '%s' successfully changed by %s\n") + : _("Size of volume '%s' successfully changed to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = true; + } else { + vshError(ctl, + delta ? _("Failed to change size of volume '%s' by %s\n") + : _("Failed to change size of volume '%s' to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = false; + } + +cleanup: + virStorageVolFree(vol); + return ret; +} + /* * "vol-dumpxml" command @@ -16139,6 +16220,7 @@ static const vshCmdDef storageVolCmds[] = { {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, + {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, {NULL, NULL, NULL, NULL, 0} diff --git a/tools/virsh.pod b/tools/virsh.pod index 8599f66..6622caf 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2012,6 +2012,17 @@ I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool the volume is in. I<vol-name-or-path> is the name or path of the volume to return the volume key for. +=item B<vol-resize> [I<--pool> I<pool-or-uuid>] I<vol-name-or-path> +I<pool-or-uuid> I<capacity> [I<--allocate>] [I<--delta>] [I<--shrink>] + +Resize the capacity of the given volume, in bytes. +I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool the volume +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. + =back =head1 SECRET COMMMANDS -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list