[libvirt] Implement virStorageVolResize() for FS backend

Zeeshan Ali (Khattak) zeeshanak at gnome.org
Mon Jan 30 07:40:11 UTC 2012


From: "Zeeshan Ali (Khattak)" <zeeshanak at 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




More information about the libvir-list mailing list