From 1c9a2fb1aef1729ac86cd6648b5c2b7584f5f698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Tomko?= Date: Wed, 5 Dec 2012 11:48:07 +0100 Subject: [PATCH] storage: allow metadata preallocation when creating qcow2 images Add VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA flag to virStorageVolCreateXML and virStorageVolCreateXMLFrom. This flag requests metadata preallocation when creating/cloning qcow2 images, resulting in creating a sparse file with qcow2 metadata. It has only slightly larger disk usage compared to new image with no allocation, but offers higher performance. --- include/libvirt/libvirt.h.in | 4 +++ src/libvirt.c | 16 ++++++++--- src/storage/storage_backend.c | 46 ++++++++++++++++++++++---------- src/storage/storage_backend.h | 3 ++- src/storage/storage_backend_fs.c | 16 ++++++----- src/storage/storage_driver.c | 6 ++--- 6 files changed, 64 insertions(+), 27 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a19f37ada1..17804ca046 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2906,6 +2906,10 @@ virStorageVolPtr virStorageVolLookupByPath (virConnectPtr conn, const char* virStorageVolGetName (virStorageVolPtr vol); const char* virStorageVolGetKey (virStorageVolPtr vol); +typedef enum { + VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA = 1 << 0, +} virStorageVolCreateFlags; + virStorageVolPtr virStorageVolCreateXML (virStoragePoolPtr pool, const char *xmldesc, unsigned int flags); diff --git a/src/libvirt.c b/src/libvirt.c index 4b7baab188..6a7a817f51 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -13382,11 +13382,16 @@ virStorageVolGetKey(virStorageVolPtr vol) * virStorageVolCreateXML: * @pool: pointer to storage pool * @xmlDesc: description of volume to create - * @flags: extra flags; not used yet, so callers should always pass 0 + * @flags: bitwise-OR of virStorageVolCreateFlags * * Create a storage volume within a pool based * on an XML description. Not all pools support - * creation of volumes + * creation of volumes. + * + * Since 1.0.1 VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA + * in flags can be used to get higher performance with + * qcow2 image files which don't support full preallocation, + * by creating a sparse image file with metadata. * * Returns the storage volume, or NULL on error */ @@ -13433,13 +13438,18 @@ error: * @pool: pointer to parent pool for the new volume * @xmlDesc: description of volume to create * @clonevol: storage volume to use as input - * @flags: extra flags; not used yet, so callers should always pass 0 + * @flags: bitwise-OR of virStorageVolCreateFlags * * Create a storage volume in the parent pool, using the * 'clonevol' volume as input. Information for the new * volume (name, perms) are passed via a typical volume * XML description. * + * Since 1.0.1 VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA + * in flags can be used to get higher performance with + * qcow2 image files which don't support full preallocation, + * by creating a sparse image file with metadata. + * * Returns the storage volume, or NULL on error */ virStorageVolPtr diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 83c4755e3a..083028d89a 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -668,8 +668,11 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, virCommandPtr cmd = NULL; bool do_encryption = (vol->target.encryption != NULL); unsigned long long int size_arg; + bool preallocate = false; - virCheckFlags(0, -1); + virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1); + + preallocate = !!(flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA); const char *type = virStorageFileFormatTypeToString(vol->target.format); const char *backingType = vol->backingStore.path ? @@ -697,11 +700,23 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, inputvol->target.format); return -1; } + if (preallocate && vol->target.format != VIR_STORAGE_FILE_QCOW2) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("metadata preallocation only available with qcow2")); + return -1; + } if (vol->backingStore.path) { int accessRetCode = -1; char *absolutePath = NULL; + if (preallocate) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("metadata preallocation conflicts with backing" + " store")); + return -1; + } + /* XXX: Not strictly required: qemu-img has an option a different * backing store, not really sure what use it serves though, and it * may cause issues with lvm. Untested essentially. @@ -796,14 +811,15 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, virCommandAddArgList(cmd, "convert", "-f", inputType, "-O", type, inputPath, vol->target.path, NULL); - if (do_encryption) { - if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) { - virCommandAddArgList(cmd, "-o", "encryption=on", NULL); - } else { - virCommandAddArg(cmd, "-e"); - } + if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS && + (do_encryption || preallocate)) { + virCommandAddArg(cmd, "-o"); + virCommandAddArgFormat(cmd, "%s%s%s", do_encryption ? "encryption=on" : "", + (do_encryption && preallocate) ? "," : "", + preallocate ? "preallocation=metadata" : ""); + } else if (do_encryption) { + virCommandAddArg(cmd, "-e"); } - } else if (vol->backingStore.path) { virCommandAddArgList(cmd, "create", "-f", type, "-b", vol->backingStore.path, NULL); @@ -840,12 +856,14 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, vol->target.path, NULL); virCommandAddArgFormat(cmd, "%lluK", size_arg); - if (do_encryption) { - if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) { - virCommandAddArgList(cmd, "-o", "encryption=on", NULL); - } else { - virCommandAddArg(cmd, "-e"); - } + if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS && + (do_encryption || preallocate)) { + virCommandAddArg(cmd, "-o"); + virCommandAddArgFormat(cmd, "%s%s%s", do_encryption ? "encryption=on" : "", + (do_encryption && preallocate) ? "," : "", + preallocate ? "preallocation=metadata" : ""); + } else if (do_encryption) { + virCommandAddArg(cmd, "-e"); } } diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h index 29cad9d4c4..c991015791 100644 --- a/src/storage/storage_backend.h +++ b/src/storage/storage_backend.h @@ -37,7 +37,8 @@ typedef int (*virStorageBackendStopPool)(virConnectPtr conn, virStoragePoolObjPt typedef int (*virStorageBackendDeletePool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags); typedef int (*virStorageBackendBuildVol)(virConnectPtr conn, - virStoragePoolObjPtr pool, virStorageVolDefPtr vol); + virStoragePoolObjPtr pool, virStorageVolDefPtr vol, + unsigned int flags); typedef int (*virStorageBackendCreateVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol); typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol); typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags); diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 6cddad00dd..fcc46b73ec 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1052,7 +1052,8 @@ static int _virStorageBackendFileSystemVolBuild(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol) + virStorageVolDefPtr inputvol, + unsigned int flags) { virStorageBackendBuildVolFrom create_func; int tool_type; @@ -1085,7 +1086,7 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn, return -1; } - if (create_func(conn, pool, vol, inputvol, 0) < 0) + if (create_func(conn, pool, vol, inputvol, flags) < 0) return -1; return 0; } @@ -1098,8 +1099,11 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn, static int virStorageBackendFileSystemVolBuild(virConnectPtr conn, virStoragePoolObjPtr pool, - virStorageVolDefPtr vol) { - return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL); + virStorageVolDefPtr vol, + unsigned int flags) { + virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1); + + return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags); } /* @@ -1112,9 +1116,9 @@ virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn, virStorageVolDefPtr inputvol, unsigned int flags) { - virCheckFlags(0, -1); + virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1); - return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol); + return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags); } /** diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 3cb231243e..c567fffc4b 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1348,7 +1348,7 @@ storageVolumeCreateXML(virStoragePoolPtr obj, virStorageVolDefPtr voldef = NULL; virStorageVolPtr ret = NULL, volobj = NULL; - virCheckFlags(0, NULL); + virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, NULL); storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); @@ -1425,7 +1425,7 @@ storageVolumeCreateXML(virStoragePoolPtr obj, voldef->building = 1; virStoragePoolObjUnlock(pool); - buildret = backend->buildVol(obj->conn, pool, buildvoldef); + buildret = backend->buildVol(obj->conn, pool, buildvoldef, flags); storageDriverLock(driver); virStoragePoolObjLock(pool); @@ -1473,7 +1473,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj, virStorageVolPtr ret = NULL, volobj = NULL; int buildret; - virCheckFlags(0, NULL); + virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, NULL); storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);