diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index e99cd003fe..d26cbbdb18 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 de635dc92d..791b267a50 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 df2aa60b93..485b578ad6 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 e9d638bc47..540d74a65f 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 1340b0c22c..8bdb24bae2 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 9b37dc0410..ffcd746b36 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 8599f66e18..6622caf3e7 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2012,6 +2012,17 @@ I<--pool> I is the name or UUID of the storage pool the volume is in. I is the name or path of the volume to return the volume key for. +=item B [I<--pool> I] I +I I [I<--allocate>] [I<--delta>] [I<--shrink>] + +Resize the capacity of the given volume, in bytes. +I<--pool> I is the name or UUID of the storage pool the volume +is in. I 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 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