From e545dd4ffe515f7fd59ffafc74f225638b5ec0a6 Mon Sep 17 00:00:00 2001 From: "Zeeshan Ali (Khattak)" Date: Mon, 30 Jan 2012 02:40:00 -0500 Subject: [PATCH] Implement virStorageVolResize() for FS backend 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 | 90 +++++++++++++++++++++++++++++++- src/util/storage_file.c | 16 ++++++ src/util/storage_file.h | 2 + 5 files changed, 166 insertions(+), 1 deletion(-) diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h index 75ed676f83..a37bf7cab1 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 d8dc29cf36..1af12e6746 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 a332ada42e..9170a17888 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1,7 +1,7 @@ /* * 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 * * This library is free software; you can redistribute it and/or @@ -1695,7 +1695,94 @@ out: 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 * 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 ba9cfc51c9..8260adbd1f 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 b8920d0d69..96afb12689 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),