resize: add virStorageVolResize() API

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@redhat.com>
This commit is contained in:
Zeeshan Ali (Khattak) 2012-01-27 07:29:56 +02:00 committed by Eric Blake
parent b2e13f9c44
commit 6714fd04d2
7 changed files with 187 additions and 0 deletions

View File

@ -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:
*

View File

@ -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 *"),

View File

@ -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;
};

View File

@ -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:

View File

@ -519,6 +519,7 @@ LIBVIRT_0.9.9 {
LIBVIRT_0.9.10 {
global:
virDomainShutdownFlags;
virStorageVolResize;
virStorageVolWipePattern;
} LIBVIRT_0.9.9;

View File

@ -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}

View File

@ -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