try to do non-shared migration without bothering to create disk images at target by hand. consider this situation: 1. non-shared migration virsh migrate --copy-storage-all ... 2. migration fails 3. create disk images required qemu-img create ... 4 migration run smoothly so, try do remove step 2, 3, 4 this kind of usage had been discussed before, http://www.redhat.com/archives/libvir-list/2011-December/msg00451.html this patch depends on my support offline migration patch: https://www.redhat.com/archives/libvir-list/2012-November/msg00512.html Signed-off-by: liguang <lig.fnst@xxxxxxxxxxxxxx> --- src/qemu/qemu_conf.h | 2 + src/qemu/qemu_driver.c | 1 + src/qemu/qemu_migration.c | 275 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 277 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 47f349c..ad789e9 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -102,6 +102,8 @@ struct qemud_driver { char *hugetlbfs_mount; char *hugepage_path; + void *private; + unsigned int macFilter : 1; ebtablesContext *ebtables; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b23056b..db11629 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1133,6 +1133,7 @@ static virDrvOpenStatus qemudOpen(virConnectPtr conn, } } } + qemu_driver->private = conn; conn->privateData = qemu_driver; return VIR_DRV_OPEN_SUCCESS; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 53171df..8b4e563 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -50,6 +50,7 @@ #include "storage_file.h" #include "viruri.h" #include "hooks.h" +#include "dirname.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -72,6 +73,7 @@ enum qemuMigrationCookieFlags { QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT, QEMU_MIGRATION_COOKIE_FLAG_NETWORK, + QEMU_MIGRATION_COOKIE_FLAG_COPYSTORAGE, QEMU_MIGRATION_COOKIE_FLAG_LAST }; @@ -79,13 +81,14 @@ enum qemuMigrationCookieFlags { VIR_ENUM_DECL(qemuMigrationCookieFlag); VIR_ENUM_IMPL(qemuMigrationCookieFlag, QEMU_MIGRATION_COOKIE_FLAG_LAST, - "graphics", "lockstate", "persistent", "network"); + "graphics", "lockstate", "persistent", "network", "storage"); enum qemuMigrationCookieFeatures { QEMU_MIGRATION_COOKIE_GRAPHICS = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS), QEMU_MIGRATION_COOKIE_LOCKSTATE = (1 << QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE), QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT), QEMU_MIGRATION_COOKIE_NETWORK = (1 << QEMU_MIGRATION_COOKIE_FLAG_NETWORK), + QEMU_MIGRATION_COOKIE_COPYSTORAGE = (1 << QEMU_MIGRATION_COOKIE_FLAG_COPYSTORAGE), }; typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; @@ -119,6 +122,19 @@ struct _qemuMigrationCookieNetwork { qemuMigrationCookieNetDataPtr net; }; +typedef struct _qemuMigrationCookieStorageData qemuMigrationCookieStorageData; +typedef qemuMigrationCookieStorageData *qemuMigrationCookieStorageDataPtr; +struct _qemuMigrationCookieStorageData { + char *dsize; +}; + +typedef struct _qemuMigrationCookieStorage qemuMigrationCookieStorage; +typedef qemuMigrationCookieStorage *qemuMigrationCookieStoragePtr; +struct _qemuMigrationCookieStorage { + int ndisks; + qemuMigrationCookieStorageDataPtr disk; +}; + typedef struct _qemuMigrationCookie qemuMigrationCookie; typedef qemuMigrationCookie *qemuMigrationCookiePtr; struct _qemuMigrationCookie { @@ -147,6 +163,9 @@ struct _qemuMigrationCookie { /* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */ qemuMigrationCookieNetworkPtr network; + + /* If (flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) */ + qemuMigrationCookieStoragePtr storage; }; static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap) @@ -175,6 +194,21 @@ qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr network) VIR_FREE(network); } +static void +qemuMigrationCookieStorageFree(qemuMigrationCookieStoragePtr storage) +{ + int i; + + if (!storage) + return; + + if (storage->disk) { + for (i = 0; i < storage->ndisks; i++) + VIR_FREE(storage->disk[i].dsize); + } + VIR_FREE(storage->disk); + VIR_FREE(storage); +} static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) { @@ -187,6 +221,9 @@ static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) if (mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) qemuMigrationCookieNetworkFree(mig->network); + if (mig->flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) + qemuMigrationCookieStorageFree(mig->storage); + VIR_FREE(mig->localHostname); VIR_FREE(mig->remoteHostname); VIR_FREE(mig->name); @@ -356,6 +393,45 @@ error: return NULL; } +static qemuMigrationCookieStoragePtr +qemuMigrationCookieStorageAlloc(struct qemud_driver *driver, + virDomainDefPtr def) +{ + int i; + qemuMigrationCookieStoragePtr mig; + virDomainBlockInfo info; + virDomainPtr dom; + virConnectPtr conn = driver->private; + + dom = virGetDomain(conn, def->name, def->uuid); + if (!dom) + goto error; + dom->id = def->id; + + if (VIR_ALLOC(mig) < 0) + goto no_memory; + if (VIR_ALLOC_N(mig->disk, def->ndisks) < 0) + goto no_memory; + + mig->ndisks = def->ndisks; + + for (i = 0; i < mig->ndisks; i++) { + if (virDomainGetBlockInfo(dom, def->disks[i]->src, + &info, 0) < 0) + goto error; + if (virAsprintf(&(mig->disk[i].dsize), "%llu", info.capacity) < 0) + goto no_memory; + } + + return mig; + +no_memory: + virReportOOMError(); +error: + qemuMigrationCookieStorageFree(mig); + return NULL; +} + static qemuMigrationCookiePtr qemuMigrationCookieNew(virDomainObjPtr dom) { @@ -491,6 +567,31 @@ qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig, return 0; } +static int qemuMigrationCookieAddStorage(qemuMigrationCookiePtr mig, + struct qemud_driver *driver, + virDomainObjPtr dom) +{ + if (mig->flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migration storage data already present")); + return -1; + } + + virDomainObjUnlock(dom); + qemuDriverUnlock(driver); + + if (dom->def->ndisks > 0) { + mig->storage = qemuMigrationCookieStorageAlloc(driver, dom->def); + if (!mig->storage) + return -1; + mig->flags |= QEMU_MIGRATION_COOKIE_COPYSTORAGE; + } + + qemuDriverLock(driver); + virDomainObjLock(dom); + + return 0; +} static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, qemuMigrationCookieGraphicsPtr grap) @@ -540,6 +641,19 @@ qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf, virBufferAddLit(buf, " </network>\n"); } +static void +qemuMigrationCookieStorageXMLFormat(virBufferPtr buf, + qemuMigrationCookieStoragePtr dsz) +{ + int i = 0; + + for (i = 0; i < dsz->ndisks; i++) { + char *dsize = dsz->disk[i].dsize; + virBufferAsprintf(buf, " <copystorage>\n"); + virBufferAsprintf(buf, " <disksize>%s</disksize>\n", dsize); + virBufferAddLit(buf, " </copystorage>\n"); + } +} static int qemuMigrationCookieXMLFormat(struct qemud_driver *driver, @@ -594,6 +708,9 @@ qemuMigrationCookieXMLFormat(struct qemud_driver *driver, if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && mig->network) qemuMigrationCookieNetworkXMLFormat(buf, mig->network); + if ((mig->flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) && mig->storage) + qemuMigrationCookieStorageXMLFormat(buf, mig->storage); + virBufferAddLit(buf, "</qemu-migration>\n"); return 0; } @@ -721,6 +838,44 @@ error: goto cleanup; } +static qemuMigrationCookieStoragePtr +qemuMigrationCookieStorageXMLParse(xmlXPathContextPtr ctxt) +{ + qemuMigrationCookieStoragePtr dsz; + int i, n; + xmlNodePtr *storage = NULL; + + if (VIR_ALLOC(dsz) < 0) + goto no_memory; + + if ((n = virXPathNodeSet("./copystorage", ctxt, &storage)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing storage information")); + goto error; + } + + dsz->ndisks = n; + if (VIR_ALLOC_N(dsz->disk, dsz->ndisks) < 0) + goto no_memory; + + for (i = 0; i < dsz->ndisks; i++) { + ctxt->node = storage[i]; + if (!(dsz->disk[i].dsize = virXPathString("string(./disksize[1])", ctxt))) + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing tlsPort attribute in migration data")); + } + +cleanup: + VIR_FREE(storage); + return dsz; + +no_memory: + virReportOOMError(); +error: + qemuMigrationCookieStorageFree(dsz); + dsz = NULL; + goto cleanup; +} static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, @@ -873,6 +1028,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, (!(mig->network = qemuMigrationCookieNetworkXMLParse(ctxt)))) goto error; + if ((flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE) && + virXPathBoolean("count(./copystorage) > 0", ctxt) && + (!(mig->storage = qemuMigrationCookieStorageXMLParse(ctxt)))) + goto error; + return 0; error: @@ -937,6 +1097,11 @@ qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, return -1; } + if (flags & QEMU_MIGRATION_COOKIE_COPYSTORAGE && + qemuMigrationCookieAddStorage(mig, driver, dom) < 0) { + return -1; + } + if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig))) return -1; @@ -1442,6 +1607,14 @@ char *qemuMigrationBegin(struct qemud_driver *driver, QEMU_MIGRATION_COOKIE_LOCKSTATE) < 0) goto cleanup; + if (flags & (VIR_MIGRATE_NON_SHARED_DISK | + VIR_MIGRATE_NON_SHARED_INC)) { + if (qemuMigrationBakeCookie(mig, driver, vm, + cookieout, cookieoutlen, + QEMU_MIGRATION_COOKIE_COPYSTORAGE) < 0) + goto cleanup; + } + if (flags & VIR_MIGRATE_OFFLINE) { if (flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) { @@ -1487,6 +1660,91 @@ cleanup: } +/* + if gen is true, find out disk images migration required, + so try to generate them at target, + if gen is false, delete disk images generated before. +*/ +static int qemuMigrationHandleDiskFiles(struct qemud_driver *driver, + virDomainDefPtr def, bool gen, + qemuMigrationCookiePtr mig) +{ + char *tmp_dir = NULL, *outbuf = NULL; + const char *img_tool = driver->qemuImgTool; + const char *disk_format[] = {"none", "raw", "none", "none", "none", + "cow", "none", "none", "qcow", "qcow2", + "qed", "vmdk", "vpc","none", "none" + }; + virCommandPtr cmd = NULL; + int i, ret = -1; + + if (!def->ndisks) + return 0; + + if (img_tool == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("unable to find kvm-img or qemu-img")); + goto error; + } + + for (i = 0; i < def->ndisks; i++) { + if (STRNEQ(def->disks[i]->driverName, "qemu")) + continue; + if (def->disks[i]->src == NULL) + continue; + if (virFileExists(def->disks[i]->src) && gen) + continue; + if (!gen && !virFileExists(def->disks[i]->src)) + continue; + if ((tmp_dir = mdir_name(def->disks[i]->src)) == NULL) + continue; + if (!virFileExists(tmp_dir)) + if (virFileMakePath(tmp_dir) < 0) + continue; + if (STREQ(disk_format[def->disks[i]->format], "none")) + continue; + if (def->disks[i]->format < VIR_STORAGE_FILE_RAW) + goto error; + if (def->disks[i]->format >= VIR_STORAGE_FILE_LAST) + goto error; + + if (gen) { + char *dsize = mig->storage->disk[i].dsize; + cmd = virCommandNewArgList(img_tool, "create", "-f", + disk_format[def->disks[i]->format], + def->disks[i]->src, NULL); + virCommandAddArgFormat(cmd, "%s", dsize); + if (def->disks[i]->encryption) + virCommandAddArgList(cmd, "-o", "encryption=on", NULL); + virCommandSetOutputBuffer(cmd, &outbuf); + if (virCommandRun(cmd, NULL) < 0) { + virReportSystemError(errno, "%s", outbuf); + goto cleanup; + } + } else { + if (unlink(def->disks[i]->src) < 0) { + virReportError(errno, "%s", _("fail to unlink disk image file")); + goto cleanup; + } + } + virCommandFree(cmd); + VIR_FREE(tmp_dir); + VIR_FREE(outbuf); + } + + ret = 0; + +cleanup: + if (ret < 0) { + virCommandFree(cmd); + VIR_FREE(tmp_dir); + VIR_FREE(outbuf); + } +error: + return ret; +} + + /* Prepare is the first step, and it runs on the destination host. */ @@ -1602,6 +1860,15 @@ qemuMigrationPrepareAny(struct qemud_driver *driver, /* virDomainAssignDef already set the error */ goto cleanup; } + + if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen, + QEMU_MIGRATION_COOKIE_COPYSTORAGE))) + goto cleanup; + + if (flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) + if (qemuMigrationHandleDiskFiles(driver, def, true, mig) < 0) + goto endjob; + def = NULL; priv = vm->privateData; priv->origname = origname; @@ -3247,6 +3514,7 @@ qemuMigrationFinish(struct qemud_driver *driver, virErrorPtr orig_err = NULL; int cookie_flags = 0; qemuDomainObjPrivatePtr priv = vm->privateData; + bool migration_status = false; VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, " "cookieout=%p, cookieoutlen=%p, flags=%lx, retcode=%d", @@ -3416,7 +3684,12 @@ qemuMigrationFinish(struct qemud_driver *driver, if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0) VIR_WARN("Unable to encode migration cookie"); + migration_status = true; + endjob: + if (!migration_status && flags & + (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) + qemuMigrationHandleDiskFiles(driver, vm->def, false, NULL); if (qemuMigrationJobFinish(driver, vm) == 0) { vm = NULL; } else if (!vm->persistent && !virDomainObjIsActive(vm)) { -- 1.7.2.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list