On Nov 21, 2012, at 8:14 PM, li guang <lig.f...@cn.fujitsu.com> wrote:
> ping ... The last review I asked that you drop the usage of qemu-img and use libvirt's block APIs and extend them as necessary to make it easier to call it. Otherwise you are duplicating functionality, not respecting the probe option, and only supporting file types supported by qemu-img. > > 在 2012-11-15四的 10:04 +0800,liguang写道: >> 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.f...@cn.fujitsu.com> >> --- >> src/qemu/qemu_migration.c | 285 >> ++++++++++++++++++++++++++++++++++++++++++++- >> 1 files changed, 284 insertions(+), 1 deletions(-) >> >> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c >> index 54359c3..9e7ee4f 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,64 @@ error: >> return NULL; >> } >> >> +static qemuMigrationCookieStoragePtr >> +qemuMigrationCookieStorageAlloc(struct qemud_driver *driver, >> + virDomainDefPtr def) >> +{ >> + int i, exitstatus; >> + char *info = NULL, *start, *end, *tmp = NULL; >> + virCommandPtr cmd = NULL; >> + qemuMigrationCookieStoragePtr mig; >> + >> + if (VIR_ALLOC(mig) < 0) >> + goto no_memory; >> + >> + if (VIR_ALLOC_N(mig->disk, def->ndisks) < 0) >> + goto no_memory; >> + if (!driver->qemuImgTool) { >> + virReportError(VIR_ERR_INTERNAL_ERROR, >> + "%s", _("unable to find kvm-img or qemu-img")); >> + goto error; >> + } >> + mig->ndisks = def->ndisks; >> + >> + for (i = 0; i < mig->ndisks; i++) { >> + cmd = virCommandNewArgList(driver->qemuImgTool, "info", >> + def->disks[i]->src, NULL); >> + virCommandAddEnvString(cmd, "LC_ALL=C"); >> + virCommandSetOutputBuffer(cmd, &info); >> + virCommandClearCaps(cmd); >> + if (virCommandRun(cmd, &exitstatus) < 0) >> + goto error; >> + if ((start = strstr(info, "virtual size: ")) == NULL || >> + ((end = strstr(start, "\n")) == NULL)) { >> + virReportError(VIR_ERR_INTERNAL_ERROR, >> + _("unable to parse qemu-img output '%s'"), >> + info); >> + goto error; >> + } >> + if ((tmp = strstr(start, " (")) && tmp < end) >> + end = tmp; >> + start += strlen("virtual size: "); >> + if (start >= end) >> + goto error; >> + if (!(mig->disk[i].dsize = strndup(start, end-start))) >> + goto error; >> + VIR_FREE(info); >> + virCommandFree(cmd); >> + } >> + >> + return mig; >> + >> +no_memory: >> + virReportOOMError(); >> +error: >> + virCommandFree(cmd); >> + VIR_FREE(info); >> + qemuMigrationCookieStorageFree(mig); >> + return NULL; >> +} >> + >> static qemuMigrationCookiePtr >> qemuMigrationCookieNew(virDomainObjPtr dom) >> { >> @@ -491,6 +586,25 @@ 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; >> + } >> + >> + if (dom->def->ndisks > 0) { >> + mig->storage = qemuMigrationCookieStorageAlloc(driver, dom->def); >> + if (!mig->storage) >> + return -1; >> + mig->flags |= QEMU_MIGRATION_COOKIE_COPYSTORAGE; >> + } >> + >> + return 0; >> +} >> >> static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, >> >> qemuMigrationCookieGraphicsPtr grap) >> @@ -540,6 +654,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 +721,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; >> } >> @@ -722,6 +852,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, >> @@ -874,6 +1042,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: >> @@ -938,6 +1111,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; >> >> @@ -1443,6 +1621,11 @@ char *qemuMigrationBegin(struct qemud_driver *driver, >> QEMU_MIGRATION_COOKIE_LOCKSTATE) < 0) >> goto cleanup; >> >> + 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)) { >> @@ -1484,6 +1667,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. >> */ >> >> @@ -1599,6 +1867,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; >> @@ -3250,6 +3527,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", >> @@ -3415,7 +3693,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)) { > > -- > li guang lig.f...@cn.fujitsu.com > linux kernel team at FNST, china > > > -- > libvir-list mailing list > libvir-list@redhat.com > https://www.redhat.com/mailman/listinfo/libvir-list -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list