[libvirt] [PATCH v1 1/2] change qemu_driver's qemuImgBinary field

qemuImgBinary is a poor name, change to qemuImgTool, and init it at qemu driver start-up phase, before this change, if we need qemu-img or kvm-img we have to call qemuFindQemuImgBinary every time, seems a little boring, from then on, we can use qemuImgTool directly, e.g. use virCommandRun(driver->qemuImgTool, ...) instead of img_tool = qemuFindQemuImgBinary(driver); qemuFindQemuImgBinary(img_tool, ...); Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> --- src/qemu/qemu_conf.h | 2 +- src/qemu/qemu_domain.c | 22 ++-------------------- src/qemu/qemu_domain.h | 2 -- src/qemu/qemu_driver.c | 12 ++++++++++-- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 2c7f70c..47f349c 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -84,7 +84,7 @@ struct qemud_driver { char *cacheDir; char *saveDir; char *snapshotDir; - char *qemuImgBinary; + char *qemuImgTool; unsigned int vncAutoUnixSocket : 1; unsigned int vncTLS : 1; unsigned int vncTLSx509verify : 1; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index e0d6951..97e4fa1 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1588,22 +1588,6 @@ cleanup: return ret; } -/* Locate an appropriate 'qemu-img' binary. */ -const char * -qemuFindQemuImgBinary(struct qemud_driver *driver) -{ - if (!driver->qemuImgBinary) { - driver->qemuImgBinary = virFindFileInPath("kvm-img"); - if (!driver->qemuImgBinary) - driver->qemuImgBinary = virFindFileInPath("qemu-img"); - if (!driver->qemuImgBinary) - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("unable to find kvm-img or qemu-img")); - } - - return driver->qemuImgBinary; -} - int qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm, virDomainSnapshotObjPtr snapshot, @@ -1659,11 +1643,9 @@ qemuDomainSnapshotForEachQcow2Raw(struct qemud_driver *driver, int i; bool skipped = false; - qemuimgarg[0] = qemuFindQemuImgBinary(driver); - if (qemuimgarg[0] == NULL) { - /* qemuFindQemuImgBinary set the error */ + qemuimgarg[0] = driver->qemuImgTool; + if (qemuimgarg[0] == NULL) return -1; - } qemuimgarg[2] = op; qemuimgarg[3] = name; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index a2acc0a..548cd20 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -300,8 +300,6 @@ int qemuDomainAppendLog(struct qemud_driver *driver, int logFD, const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(4, 5); -const char *qemuFindQemuImgBinary(struct qemud_driver *driver); - int qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm, virDomainSnapshotObjPtr snapshot, char *snapshotDir); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 436e853..e87e7b4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -643,6 +643,14 @@ qemudStartup(int privileged) { if (!qemu_driver->domainEventState) goto error; + /* find kvm-img or qemu-img */ + qemu_driver->qemuImgTool = virFindFileInPath("kvm-img"); + if (!qemu_driver->qemuImgTool) + qemu_driver->qemuImgTool = virFindFileInPath("qemu-img"); + if (!qemu_driver->qemuImgTool) + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("unable to find kvm-img or qemu-img")); + /* read the host sysinfo */ if (privileged) qemu_driver->hostsysinfo = virSysinfoRead(); @@ -1029,7 +1037,7 @@ qemudShutdown(void) { VIR_FREE(qemu_driver->cacheDir); VIR_FREE(qemu_driver->saveDir); VIR_FREE(qemu_driver->snapshotDir); - VIR_FREE(qemu_driver->qemuImgBinary); + VIR_FREE(qemu_driver->qemuImgTool); VIR_FREE(qemu_driver->autoDumpPath); VIR_FREE(qemu_driver->vncTLSx509certdir); VIR_FREE(qemu_driver->vncListen); @@ -10706,7 +10714,7 @@ qemuDomainSnapshotCreateInactiveExternal(struct qemud_driver *driver, int ret = -1; - if (!(qemuImgPath = qemuFindQemuImgBinary(driver))) + if (!(qemuImgPath = driver->qemuImgTool)) return -1; if (!(created = virBitmapNew(snap->def->ndisks))) { -- 1.7.1

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@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)) { -- 1.7.1

On Wed, Nov 14, 2012 at 8:04 PM, liguang <lig.fnst@cn.fujitsu.com> wrote:
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@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");
You're still using a qemu-img callout directly rather than using the existing block storage API. This whole function is really just an implementation of qemuDomainGetBlockInfo().
+ 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)) { -- 1.7.1
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Doug Goldstein

在 2012-11-15四的 14:09 -0600,Doug Goldstein写道: big cut ...
+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");
You're still using a qemu-img callout directly rather than using the existing block storage API. This whole function is really just an implementation of qemuDomainGetBlockInfo().
can you imagine how to use qemuDomainGetBlockInfo from here? seems hard to grab "virDomainPtr dom" at present? maybe I should change more to adopt this function for getting a parameter "dom" or "conn". or, any good idea? Thanks!
+ 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)) { -- 1.7.1
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- li guang lig.fnst@cn.fujitsu.com linux kernel team at FNST, china

ping ... 在 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.fnst@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.fnst@cn.fujitsu.com linux kernel team at FNST, china

On Nov 21, 2012, at 8:14 PM, li guang <lig.fnst@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.fnst@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.fnst@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

在 2012-11-21三的 23:21 -0600,Doug Goldstein写道:
On Nov 21, 2012, at 8:14 PM, li guang <lig.fnst@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.
yes, I'm considering your opinion, but, seems it's not so convenience to use that function, you know? or do you have a suitable way to call it during MigrationPrepareAny?
在 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.fnst@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.fnst@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
-- li guang lig.fnst@cn.fujitsu.com linux kernel team at FNST, china

On Nov 21, 2012, at 11:41 PM, li guang <lig.fnst@cn.fujitsu.com> wrote:
在 2012-11-21三的 23:21 -0600,Doug Goldstein写道:
On Nov 21, 2012, at 8:14 PM, li guang <lig.fnst@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.
yes, I'm considering your opinion, but, seems it's not so convenience to use that function, you know?
All the pieces are available if I recall when I looked before. I believe I suggested splitting the function into too since there was some unnecessary up front bits being done that would make the args even easier. When I get back to a PC I can hack up a patch.
or do you have a suitable way to call it during MigrationPrepareAny?
在 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.fnst@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.fnst@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
-- li guang lig.fnst@cn.fujitsu.com linux kernel team at FNST, china

在 2012-11-22四的 13:41 +0800,li guang写道:
在 2012-11-21三的 23:21 -0600,Doug Goldstein写道:
On Nov 21, 2012, at 8:14 PM, li guang <lig.fnst@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.
yes, I'm considering your opinion, but, seems it's not so convenience to use that function, you know? or do you have a suitable way to call it during MigrationPrepareAny?
I mean during BakeCookie, it's hard to grab a virDomainPtr parameter for qemuDomainGetBlockInfo, and also it's unusual to BakeCookie for storage at qemu_driver.c. I've said this several days ago.
在 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.fnst@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.fnst@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
-- li guang lig.fnst@cn.fujitsu.com linux kernel team at FNST, china
participants (4)
-
Doug Goldstein
-
Doug Goldstein
-
li guang
-
liguang