[libvirt] Implement virStorageVolResize() for FS backend

From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org> Currently only VIR_STORAGE_VOL_RESIZE_DELTA flag is supported. --- src/storage/storage_backend.h | 6 +++ src/storage/storage_backend_fs.c | 53 +++++++++++++++++++++++ src/storage/storage_driver.c | 88 ++++++++++++++++++++++++++++++++++++++ src/util/storage_file.c | 16 +++++++ src/util/storage_file.h | 2 + 5 files changed, 165 insertions(+), 0 deletions(-) diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h index 75ed676..a37bf7c 100644 --- a/src/storage/storage_backend.h +++ b/src/storage/storage_backend.h @@ -44,6 +44,11 @@ typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjP typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr origvol, virStorageVolDefPtr newvol, 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 */ int virStorageBackendCreateRaw(virConnectPtr conn, @@ -78,6 +83,7 @@ struct _virStorageBackend { virStorageBackendCreateVol createVol; virStorageBackendRefreshVol refreshVol; virStorageBackendDeleteVol deleteVol; + virStorageBackendVolumeResize resizeVol; }; virStorageBackendPtr virStorageBackendForType(int type); diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index d8dc29c..1af12e6 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1187,6 +1187,56 @@ virStorageBackendFileSystemVolRefresh(virConnectPtr conn, 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 = { .type = VIR_STORAGE_POOL_DIR, @@ -1199,6 +1249,7 @@ virStorageBackend virStorageBackendDirectory = { .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, + .resizeVol = virStorageBackendFileSystemVolResize, }; #if WITH_STORAGE_FS @@ -1216,6 +1267,7 @@ virStorageBackend virStorageBackendFileSystem = { .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, + .resizeVol = virStorageBackendFileSystemVolResize, }; virStorageBackend virStorageBackendNetFileSystem = { .type = VIR_STORAGE_POOL_NETFS, @@ -1232,5 +1284,6 @@ virStorageBackend virStorageBackendNetFileSystem = { .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, + .resizeVol = virStorageBackendFileSystemVolResize, }; #endif /* WITH_STORAGE_FS */ diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index a332ada..e7a8a8b 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1695,7 +1695,94 @@ out: return ret; } +static int +storageVolumeResize(virStorageVolPtr obj, + 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 * truncate and extend it to its original size, filling it with @@ -2243,6 +2330,7 @@ static virStorageDriver storageDriver = { .volGetInfo = storageVolumeGetInfo, /* 0.4.0 */ .volGetXMLDesc = storageVolumeGetXMLDesc, /* 0.4.0 */ .volGetPath = storageVolumeGetPath, /* 0.4.0 */ + .volResize = storageVolumeResize, /* 0.9.10 */ .poolIsActive = storagePoolIsActive, /* 0.7.3 */ .poolIsPersistent = storagePoolIsPersistent, /* 0.7.3 */ diff --git a/src/util/storage_file.c b/src/util/storage_file.c index ba9cfc5..8260adb 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -931,6 +931,22 @@ virStorageFileFreeMetadata(virStorageFileMetadata *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__ # ifndef NFS_SUPER_MAGIC diff --git a/src/util/storage_file.h b/src/util/storage_file.h index b8920d0..96afb12 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -72,6 +72,8 @@ int virStorageFileGetMetadataFromFD(const char *path, void virStorageFileFreeMetadata(virStorageFileMetadata *meta); +int virStorageFileResize(const char *path, unsigned long long capacity); + enum { VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1), -- 1.7.7.6

On Mon, Jan 30, 2012 at 09:40:11AM +0200, Zeeshan Ali (Khattak) wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org>
Currently only VIR_STORAGE_VOL_RESIZE_DELTA flag is supported. --- src/storage/storage_backend.h | 6 +++ src/storage/storage_backend_fs.c | 53 +++++++++++++++++++++++ src/storage/storage_driver.c | 88 ++++++++++++++++++++++++++++++++++++++ src/util/storage_file.c | 16 +++++++ src/util/storage_file.h | 2 + 5 files changed, 165 insertions(+), 0 deletions(-)
ACK, looks ok to me. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 01/31/2012 05:15 AM, Daniel P. Berrange wrote:
On Mon, Jan 30, 2012 at 09:40:11AM +0200, Zeeshan Ali (Khattak) wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org>
Currently only VIR_STORAGE_VOL_RESIZE_DELTA flag is supported. --- src/storage/storage_backend.h | 6 +++ src/storage/storage_backend_fs.c | 53 +++++++++++++++++++++++ src/storage/storage_driver.c | 88 ++++++++++++++++++++++++++++++++++++++ src/util/storage_file.c | 16 +++++++ src/util/storage_file.h | 2 + 5 files changed, 165 insertions(+), 0 deletions(-)
ACK, looks ok to me.
For closure purposes, Laine pushed my patch changing capacity to unsigned long long, then this patch with the correct type. You're still welcome to implement support for more flags between now and 0.9.10. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Zeeshan Ali (Khattak)