Implement virStorageVolResize() for FS backend

Currently only VIR_STORAGE_VOL_RESIZE_DELTA flag is supported.
This commit is contained in:
Zeeshan Ali (Khattak) 2012-01-30 02:40:00 -05:00 committed by Laine Stump
parent 055bbf45e4
commit e545dd4ffe
5 changed files with 166 additions and 1 deletions

View File

@ -44,6 +44,11 @@ typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjP
typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool, typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool,
virStorageVolDefPtr origvol, virStorageVolDefPtr newvol, virStorageVolDefPtr origvol, virStorageVolDefPtr newvol,
unsigned int flags); unsigned int flags);
typedef int (*virStorageBackendVolumeResize)(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
unsigned long long capacity,
unsigned int flags);
/* File creation/cloning functions used for cloning between backends */ /* File creation/cloning functions used for cloning between backends */
int virStorageBackendCreateRaw(virConnectPtr conn, int virStorageBackendCreateRaw(virConnectPtr conn,
@ -78,6 +83,7 @@ struct _virStorageBackend {
virStorageBackendCreateVol createVol; virStorageBackendCreateVol createVol;
virStorageBackendRefreshVol refreshVol; virStorageBackendRefreshVol refreshVol;
virStorageBackendDeleteVol deleteVol; virStorageBackendDeleteVol deleteVol;
virStorageBackendVolumeResize resizeVol;
}; };
virStorageBackendPtr virStorageBackendForType(int type); virStorageBackendPtr virStorageBackendForType(int type);

View File

@ -1187,6 +1187,56 @@ virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
return 0; return 0;
} }
static int
virStorageBackendFilesystemResizeQemuImg(const char *path,
unsigned long long capacity)
{
int ret = -1;
char *img_tool;
virCommandPtr cmd = NULL;
/* KVM is usually ahead of qemu on features, so try that first */
img_tool = virFindFileInPath("kvm-img");
if (!img_tool)
img_tool = virFindFileInPath("qemu-img");
if (!img_tool) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unable to find kvm-img or qemu-img"));
return -1;
}
cmd = virCommandNew(img_tool);
virCommandAddArgList(cmd, "resize", path, NULL);
virCommandAddArgFormat(cmd, "%llu", capacity);
ret = virCommandRun(cmd, NULL);
VIR_FREE(img_tool);
virCommandFree(cmd);
return ret;
}
/**
* Resize a volume
*/
static int
virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol,
unsigned long long capacity,
unsigned int flags)
{
virCheckFlags(0, -1);
if (vol->target.format == VIR_STORAGE_FILE_RAW)
return virStorageFileResize(vol->target.path, capacity);
else
return virStorageBackendFilesystemResizeQemuImg(vol->target.path,
capacity);
}
virStorageBackend virStorageBackendDirectory = { virStorageBackend virStorageBackendDirectory = {
.type = VIR_STORAGE_POOL_DIR, .type = VIR_STORAGE_POOL_DIR,
@ -1199,6 +1249,7 @@ virStorageBackend virStorageBackendDirectory = {
.createVol = virStorageBackendFileSystemVolCreate, .createVol = virStorageBackendFileSystemVolCreate,
.refreshVol = virStorageBackendFileSystemVolRefresh, .refreshVol = virStorageBackendFileSystemVolRefresh,
.deleteVol = virStorageBackendFileSystemVolDelete, .deleteVol = virStorageBackendFileSystemVolDelete,
.resizeVol = virStorageBackendFileSystemVolResize,
}; };
#if WITH_STORAGE_FS #if WITH_STORAGE_FS
@ -1216,6 +1267,7 @@ virStorageBackend virStorageBackendFileSystem = {
.createVol = virStorageBackendFileSystemVolCreate, .createVol = virStorageBackendFileSystemVolCreate,
.refreshVol = virStorageBackendFileSystemVolRefresh, .refreshVol = virStorageBackendFileSystemVolRefresh,
.deleteVol = virStorageBackendFileSystemVolDelete, .deleteVol = virStorageBackendFileSystemVolDelete,
.resizeVol = virStorageBackendFileSystemVolResize,
}; };
virStorageBackend virStorageBackendNetFileSystem = { virStorageBackend virStorageBackendNetFileSystem = {
.type = VIR_STORAGE_POOL_NETFS, .type = VIR_STORAGE_POOL_NETFS,
@ -1232,5 +1284,6 @@ virStorageBackend virStorageBackendNetFileSystem = {
.createVol = virStorageBackendFileSystemVolCreate, .createVol = virStorageBackendFileSystemVolCreate,
.refreshVol = virStorageBackendFileSystemVolRefresh, .refreshVol = virStorageBackendFileSystemVolRefresh,
.deleteVol = virStorageBackendFileSystemVolDelete, .deleteVol = virStorageBackendFileSystemVolDelete,
.resizeVol = virStorageBackendFileSystemVolResize,
}; };
#endif /* WITH_STORAGE_FS */ #endif /* WITH_STORAGE_FS */

View File

@ -1,7 +1,7 @@
/* /*
* storage_driver.c: core driver for storage APIs * storage_driver.c: core driver for storage APIs
* *
* Copyright (C) 2006-2011 Red Hat, Inc. * Copyright (C) 2006-2012 Red Hat, Inc.
* Copyright (C) 2006-2008 Daniel P. Berrange * Copyright (C) 2006-2008 Daniel P. Berrange
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -1695,7 +1695,94 @@ out:
return ret; return ret;
} }
static int
storageVolumeResize(virStorageVolPtr obj,
unsigned long long capacity,
unsigned int flags)
{
virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
virStorageBackendPtr backend;
virStoragePoolObjPtr pool = NULL;
virStorageVolDefPtr vol = NULL;
unsigned long long abs_capacity;
int ret = -1;
virCheckFlags(VIR_STORAGE_VOL_RESIZE_DELTA, -1);
storageDriverLock(driver);
pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
storageDriverUnlock(driver);
if (!pool) {
virStorageReportError(VIR_ERR_NO_STORAGE_POOL,
_("no storage pool with matching uuid"));
goto out;
}
if (!virStoragePoolObjIsActive(pool)) {
virStorageReportError(VIR_ERR_OPERATION_INVALID,
_("storage pool is not active"));
goto out;
}
if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
goto out;
vol = virStorageVolDefFindByName(pool, obj->name);
if (vol == NULL) {
virStorageReportError(VIR_ERR_NO_STORAGE_VOL,
_("no storage vol with matching name '%s'"),
obj->name);
goto out;
}
if (vol->building) {
virStorageReportError(VIR_ERR_OPERATION_INVALID,
_("volume '%s' is still being allocated."),
vol->name);
goto out;
}
if (flags & VIR_STORAGE_VOL_RESIZE_DELTA) {
abs_capacity = vol->capacity + capacity;
flags &= ~VIR_STORAGE_VOL_RESIZE_DELTA;
} else {
abs_capacity = capacity;
}
if (abs_capacity < vol->allocation) {
virStorageReportError(VIR_ERR_INVALID_ARG,
_("can't shrink capacity below "
"existing allocation"));
goto out;
}
if (abs_capacity > vol->allocation + pool->def->available) {
virStorageReportError(VIR_ERR_INVALID_ARG,
_("Not enough space left on storage pool"));
goto out;
}
if (!backend->resizeVol) {
virStorageReportError(VIR_ERR_NO_SUPPORT,
_("storage pool does not support changing of "
"volume capacity"));
goto out;
}
if (backend->resizeVol(obj->conn, pool, vol, abs_capacity, flags) < 0)
goto out;
vol->capacity = abs_capacity;
ret = 0;
out:
if (pool)
virStoragePoolObjUnlock(pool);
return ret;
}
/* If the volume we're wiping is already a sparse file, we simply /* If the volume we're wiping is already a sparse file, we simply
* truncate and extend it to its original size, filling it with * truncate and extend it to its original size, filling it with
@ -2243,6 +2330,7 @@ static virStorageDriver storageDriver = {
.volGetInfo = storageVolumeGetInfo, /* 0.4.0 */ .volGetInfo = storageVolumeGetInfo, /* 0.4.0 */
.volGetXMLDesc = storageVolumeGetXMLDesc, /* 0.4.0 */ .volGetXMLDesc = storageVolumeGetXMLDesc, /* 0.4.0 */
.volGetPath = storageVolumeGetPath, /* 0.4.0 */ .volGetPath = storageVolumeGetPath, /* 0.4.0 */
.volResize = storageVolumeResize, /* 0.9.10 */
.poolIsActive = storagePoolIsActive, /* 0.7.3 */ .poolIsActive = storagePoolIsActive, /* 0.7.3 */
.poolIsPersistent = storagePoolIsPersistent, /* 0.7.3 */ .poolIsPersistent = storagePoolIsPersistent, /* 0.7.3 */

View File

@ -931,6 +931,22 @@ virStorageFileFreeMetadata(virStorageFileMetadata *meta)
VIR_FREE(meta); VIR_FREE(meta);
} }
/**
* virStorageFileResize:
*
* Change the capacity of the raw storage file at 'path'.
*/
int
virStorageFileResize(const char *path, unsigned long long capacity)
{
if (truncate(path, capacity) < 0) {
virReportSystemError(errno, _("Failed to truncate file '%s'"), path);
return -1;
}
return 0;
}
#ifdef __linux__ #ifdef __linux__
# ifndef NFS_SUPER_MAGIC # ifndef NFS_SUPER_MAGIC

View File

@ -72,6 +72,8 @@ int virStorageFileGetMetadataFromFD(const char *path,
void virStorageFileFreeMetadata(virStorageFileMetadata *meta); void virStorageFileFreeMetadata(virStorageFileMetadata *meta);
int virStorageFileResize(const char *path, unsigned long long capacity);
enum { enum {
VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), VIR_STORAGE_FILE_SHFS_NFS = (1 << 0),
VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1), VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1),