[libvirt] [PATCH v2 4/4] qemu_migration: Precreate missing storage
Peter Krempa
pkrempa at redhat.com
Tue Dec 2 10:53:29 UTC 2014
On 12/01/14 15:57, Michal Privoznik wrote:
> Based on previous commit, we can now precreate missing volumes. While
> digging out the functionality from storage driver would be nicer, if
> you've seen the code it's nearly impossible. So I'm going from the
> other end:
>
> 1) For given disk target, disk path is looked up.
> 2) For the disk path, storage pool is looked up, a volume XML is
> constructed and then passed to virStorageVolCreateXML() which has all
> the knowledge how to create raw images, (encrypted) qcow(2) images,
> etc.
>
> One of the advantages of this approach is, we don't have to care about
> image conversion - qemu does that for us. So for instance, users can
> transform qcow2 into raw on migration (if the correct XML is passed to
> the migration API).
>
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
> src/qemu/qemu_migration.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 150 insertions(+)
>
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 26df9c7..9ccfee2 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -58,6 +58,7 @@
> #include "virtypedparam.h"
> #include "virprocess.h"
> #include "nwfilter_conf.h"
> +#include "storage/storage_driver.h"
>
> #define VIR_FROM_THIS VIR_FROM_QEMU
>
> @@ -1454,6 +1455,152 @@ qemuMigrationRestoreDomainState(virConnectPtr conn, virDomainObjPtr vm)
> return ret;
> }
>
> +
> +static int
> +qemuMigrationPrecreateDisk(virConnectPtr conn,
> + virDomainDiskDefPtr disk,
> + unsigned long long capacity)
> +{
> + int ret = -1;
> + virStoragePoolPtr pool = NULL;
> + virStorageVolPtr vol = NULL;
> + char *volName = NULL, *basePath = NULL;
> + char *volStr = NULL;
> + virBuffer buf = VIR_BUFFER_INITIALIZER;
> + const char *format = NULL;
> + unsigned int flags = 0;
> +
> + VIR_DEBUG("Precreate disk type=%s", virStorageTypeToString(disk->src->type));
> +
> + switch ((virStorageType) disk->src->type) {
> + case VIR_STORAGE_TYPE_FILE:
> + if (!virDomainDiskGetSource(disk)) {
> + VIR_DEBUG("Dropping sourceless disk '%s'",
> + disk->dst);
> + return 0;
> + }
> +
> + if (VIR_STRDUP(basePath, disk->src->path) < 0)
> + goto cleanup;
> +
> + if (!(volName = strrchr(basePath, '/'))) {
For finding the base path you'd normally want to use mdir_name(), but
then you wouldn't be able to extract the volume name too.
> + virReportError(VIR_ERR_INVALID_ARG,
> + _("malformed disk path: %s"),
> + disk->src->path);
> + goto cleanup;
> + }
> +
> + *volName = '\0';
> + volName++;
I guess this is good enough then.
> +
> + if (!(pool = storagePoolLookupByPath(conn, basePath))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("unable to find pool to %s"),
"unable to find pool for path '%s'" ?
> + basePath);
> + goto cleanup;
> + }
> + format = virStorageFileFormatTypeToString(disk->src->format);
> + if (disk->src->format == VIR_STORAGE_FILE_QCOW2)
> + flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
> + break;
> +
> + case VIR_STORAGE_TYPE_VOLUME:
> + if (!(pool = virStoragePoolLookupByName(conn, disk->src->srcpool->pool)))
> + goto cleanup;
> + format = virStorageFileFormatTypeToString(disk->src->format);
> + volName = disk->src->srcpool->volume;
> + if (disk->src->format == VIR_STORAGE_FILE_QCOW2)
> + flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
> + break;
> +
> + case VIR_STORAGE_TYPE_BLOCK:
> + case VIR_STORAGE_TYPE_DIR:
> + case VIR_STORAGE_TYPE_NETWORK:
> + case VIR_STORAGE_TYPE_NONE:
> + case VIR_STORAGE_TYPE_LAST:
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("unsupported disk type '%s'"),
Possibly a more helpful message: "cannot precreate storage for disk type
'%s' ?
> + virStorageTypeToString(disk->src->type));
> + goto cleanup;
> + break;
> + }
> +
> + virBufferAddLit(&buf, "<volume>\n");
> + virBufferAdjustIndent(&buf, 2);
> + virBufferAsprintf(&buf, "<name>%s</name>", volName);
You need to use virBufferEscape for the name
> + virBufferAsprintf(&buf, "<capacity>%llu</capacity>\n", capacity);
> + virBufferAddLit(&buf, "<target>\n");
> + virBufferAdjustIndent(&buf, 2);
> + virBufferAsprintf(&buf, "<format type='%s'/>\n", format);
Format is okay as we control the strings.
> + virBufferAdjustIndent(&buf, -2);
> + virBufferAddLit(&buf, "</target>\n");
> + virBufferAdjustIndent(&buf, -2);
> + virBufferAddLit(&buf, "</volume>\n");
> +
> + if (!(volStr = virBufferContentAndReset(&buf))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("unable to create volume XML"));
> + goto cleanup;
> + }
> +
> + if (!(vol = virStorageVolCreateXML(pool, volStr, flags)))
> + goto cleanup;
> +
> + ret = 0;
> + cleanup:
> + VIR_FREE(basePath);
> + VIR_FREE(volStr);
> + if (vol)
> + virStorageVolFree(vol);
> + if (pool)
> + virStoragePoolFree(pool);
> + return ret;
> +}
> +
> +
> +static int
> +qemuMigrationPrecreateStorage(virConnectPtr conn,
> + virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
> + virDomainObjPtr vm,
> + qemuMigrationCookieNBDPtr nbd)
> +{
> + int ret = -1;
> + size_t i = 0;
> +
> + if (!nbd || !nbd->ndisks)
> + return 0;
> +
> + for (i = 0; i < nbd->ndisks; i++) {
> + virDomainDiskDefPtr disk;
> + int indx;
> + const char *diskSrcPath;
> +
> + VIR_DEBUG("Looking up disk target '%s' (capacity=%lluu)",
> + nbd->disks[i].target, nbd->disks[i].capacity);
> +
> + if ((indx = virDomainDiskIndexByName(vm->def,
> + nbd->disks[i].target, false)) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("unable to find disk by target: %s"),
> + nbd->disks[i].target);
> + goto cleanup;
> + }
> +
> + disk = vm->def->disks[indx];
> + diskSrcPath = virDomainDiskGetSource(disk);
> +
> + VIR_DEBUG("Proceeding with disk source %s", NULLSTR(diskSrcPath));
The storage pre-creation should be skipped in case the target file
already exists as previously the user had to pre-create the file
manually. In case we'd do this unconditionally we might break the case
somebody is already precreating it.
> +
> + if (qemuMigrationPrecreateDisk(conn, disk, nbd->disks[i].capacity) < 0)
> + goto cleanup;
> + }
> +
> + ret = 0;
> + cleanup:
> + return ret;
> +}
> +
> +
> /**
> * qemuMigrationStartNBDServer:
> * @driver: qemu driver
> @@ -2838,6 +2985,9 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
> goto cleanup;
> }
>
> + if (qemuMigrationPrecreateStorage(dconn, driver, vm, mig->nbd) < 0)
> + goto cleanup;
> +
> if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
> goto cleanup;
> qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PREPARE);
>
Otherwise looks good code-wise, but I don't see any mention of this new
feature in the documentation.
Peter
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20141202/fc55e137/attachment-0001.sig>
More information about the libvir-list
mailing list