[libvirt] [PATCH 0/5] fix destination domain synchronization

Patch 4 is main one. Others are fixes and ground works. Nikolay Shirokovskiy (5): vz: don't pass empty and unused fields in migration cookie vz: fix missed defined domain event vz: fix memory leaks in prlsdkLoadDomains vz: fix destination domain synchronization vz: issue domain undefined event on finish step if needed src/vz/vz_driver.c | 175 ++++++++++++++++++++++++++++------------------------- src/vz/vz_sdk.c | 28 ++++++--- src/vz/vz_sdk.h | 5 ++ 3 files changed, 118 insertions(+), 90 deletions(-) -- 1.8.3.1

The first version of migration cookie was rather dumb resulting in passing empty or unused fields here and there. Add flags to specify what to bake to and eat from cookie so we deal only with meaningful data. However for backwards compatibility we still need to pass at least some faked fields sometimes. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 109 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 41 deletions(-) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 177a57a..a404666 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -2103,11 +2103,17 @@ vzDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags) return ret; } +enum vzMigrationCookieFeatures { + VZ_MIGRATION_COOKIE_SESSION_UUID = (1 << 0), + VZ_MIGRATION_COOKIE_DOMAIN_UUID = (1 << 1), + VZ_MIGRATION_COOKIE_DOMAIN_NAME = (1 << 1), +}; + typedef struct _vzMigrationCookie vzMigrationCookie; typedef vzMigrationCookie *vzMigrationCookiePtr; struct _vzMigrationCookie { - unsigned char session_uuid[VIR_UUID_BUFLEN]; - unsigned char uuid[VIR_UUID_BUFLEN]; + unsigned char *session_uuid; + unsigned char *uuid; char *name; }; @@ -2116,12 +2122,18 @@ vzMigrationCookieFree(vzMigrationCookiePtr mig) { if (!mig) return; + + VIR_FREE(mig->session_uuid); + VIR_FREE(mig->uuid); VIR_FREE(mig->name); VIR_FREE(mig); } static int -vzBakeCookie(vzMigrationCookiePtr mig, char **cookieout, int *cookieoutlen) +vzBakeCookie(vzDriverPtr driver, + virDomainObjPtr dom, + char **cookieout, int *cookieoutlen, + unsigned int flags) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -2137,11 +2149,28 @@ vzBakeCookie(vzMigrationCookiePtr mig, char **cookieout, int *cookieoutlen) virBufferAddLit(&buf, "<vz-migration>\n"); virBufferAdjustIndent(&buf, 2); - virUUIDFormat(mig->session_uuid, uuidstr); - virBufferAsprintf(&buf, "<session-uuid>%s</session-uuid>\n", uuidstr); - virUUIDFormat(mig->uuid, uuidstr); - virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr); - virBufferAsprintf(&buf, "<name>%s</name>\n", mig->name); + + if (flags & VZ_MIGRATION_COOKIE_SESSION_UUID) { + virUUIDFormat(driver->session_uuid, uuidstr); + virBufferAsprintf(&buf, "<session-uuid>%s</session-uuid>\n", uuidstr); + } + + if (flags & VZ_MIGRATION_COOKIE_DOMAIN_UUID) { + unsigned char fakeuuid[VIR_UUID_BUFLEN] = { 0 }; + + /* if dom is NULL just pass some parsable uuid for backward compat. + * It is not used by peer */ + virUUIDFormat(dom ? dom->def->uuid : fakeuuid, uuidstr); + virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr); + } + + if (flags & VZ_MIGRATION_COOKIE_DOMAIN_NAME) { + /* if dom is NULL just pass some name for backward compat. + * It is not used by peer */ + virBufferAsprintf(&buf, "<name>%s</name>\n", dom ? dom->def->name : + "__fakename__"); + } + virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, "</vz-migration>\n"); @@ -2155,11 +2184,11 @@ vzBakeCookie(vzMigrationCookiePtr mig, char **cookieout, int *cookieoutlen) } static vzMigrationCookiePtr -vzEatCookie(const char *cookiein, int cookieinlen) +vzEatCookie(const char *cookiein, int cookieinlen, unsigned int flags) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctx = NULL; - char *tmp; + char *tmp = NULL; vzMigrationCookiePtr mig = NULL; if (VIR_ALLOC(mig) < 0) @@ -2175,33 +2204,31 @@ vzEatCookie(const char *cookiein, int cookieinlen) _("(_migration_cookie)"), &ctx))) goto error; - if (!(tmp = virXPathString("string(./session-uuid[1])", ctx))) { + if ((flags & VZ_MIGRATION_COOKIE_SESSION_UUID) + && (!(tmp = virXPathString("string(./session-uuid[1])", ctx)) + || (VIR_ALLOC_N(mig->session_uuid, VIR_UUID_BUFLEN) < 0) + || (virUUIDParse(tmp, mig->session_uuid) < 0))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("missing session-uuid element in migration data")); - goto error; - } - if (virUUIDParse(tmp, mig->session_uuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("malformed session-uuid element in migration data")); + _("missing or malformed session-uuid element " + "in migration data")); VIR_FREE(tmp); goto error; } VIR_FREE(tmp); - if (!(tmp = virXPathString("string(./uuid[1])", ctx))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("missing uuid element in migration data")); - goto error; - } - if (virUUIDParse(tmp, mig->uuid) < 0) { + if ((flags & VZ_MIGRATION_COOKIE_DOMAIN_UUID) + && (!(tmp = virXPathString("string(./uuid[1])", ctx)) + || (VIR_ALLOC_N(mig->uuid, VIR_UUID_BUFLEN) < 0) + || (virUUIDParse(tmp, mig->uuid) < 0))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("malformed uuid element in migration data")); + _("missing or malformed uuid element in migration data")); VIR_FREE(tmp); goto error; } VIR_FREE(tmp); - if (!(mig->name = virXPathString("string(./name[1])", ctx))) { + if ((flags & VZ_MIGRATION_COOKIE_DOMAIN_NAME) + && !(mig->name = virXPathString("string(./name[1])", ctx))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing name element in migration data")); goto error; @@ -2238,7 +2265,6 @@ vzDomainMigrateBegin3Params(virDomainPtr domain, char *xml = NULL; virDomainObjPtr dom = NULL; vzConnPtr privconn = domain->conn->privateData; - vzMigrationCookiePtr mig = NULL; virCheckFlags(VZ_MIGRATION_FLAGS, NULL); @@ -2257,15 +2283,11 @@ vzDomainMigrateBegin3Params(virDomainPtr domain, if (!(dom = vzDomObjFromDomain(domain))) goto cleanup; - if (VIR_ALLOC(mig) < 0) - goto cleanup; - - if (VIR_STRDUP(mig->name, dom->def->name) < 0) - goto cleanup; - - memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN); - - if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + /* session uuid is for backward compat */ + if (vzBakeCookie(privconn->driver, dom, cookieout, cookieoutlen, + VZ_MIGRATION_COOKIE_SESSION_UUID + | VZ_MIGRATION_COOKIE_DOMAIN_UUID + | VZ_MIGRATION_COOKIE_DOMAIN_NAME) < 0) goto cleanup; xml = virDomainDefFormat(dom->def, privconn->driver->caps, @@ -2273,7 +2295,6 @@ vzDomainMigrateBegin3Params(virDomainPtr domain, cleanup: - vzMigrationCookieFree(mig); if (dom) virObjectUnlock(dom); return xml; @@ -2337,12 +2358,17 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, if (!miguri && !(*uri_out = vzMigrationCreateURI())) goto cleanup; - if (!(mig = vzEatCookie(cookiein, cookieinlen))) + if (!(mig = vzEatCookie(cookiein, cookieinlen, + VZ_MIGRATION_COOKIE_DOMAIN_UUID + | VZ_MIGRATION_COOKIE_DOMAIN_NAME))) goto cleanup; - memcpy(mig->session_uuid, privconn->driver->session_uuid, VIR_UUID_BUFLEN); - - if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + /* domain uuid and domain name are for backward compat */ + if (vzBakeCookie(privconn->driver, NULL, + cookieout, cookieoutlen, + VZ_MIGRATION_COOKIE_SESSION_UUID + | VZ_MIGRATION_COOKIE_DOMAIN_UUID + | VZ_MIGRATION_COOKIE_DOMAIN_NAME) < 0) goto cleanup; virObjectLock(privconn->driver); @@ -2453,7 +2479,8 @@ vzDomainMigratePerformStep(virDomainPtr domain, goto cleanup; } - if (!(mig = vzEatCookie(cookiein, cookieinlen))) + if (!(mig = vzEatCookie(cookiein, cookieinlen, + VZ_MIGRATION_COOKIE_SESSION_UUID))) goto cleanup; if (!(dom = vzDomObjFromDomain(domain))) -- 1.8.3.1

libvirt domain defined event is issued only on correspondent vz sdk event. But in case event delivered before domain is added to domain list we can mistakenly skip this event if prlsdkNewDomainByHandle return NULL in case of domain is discovered in the list under the driver lock. Let's return domain object in this case. Now prlsdkNewDomainByHandle returns NULL only in case of error which is more convinient. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 7eb78ca..e7e9638 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -1255,12 +1255,8 @@ prlsdkNewDomainByHandle(vzDriverPtr driver, PRL_HANDLE sdkdom) goto cleanup; /* we should make sure that there is no such a VM exists */ - dom = virDomainObjListFindByUUID(driver->domains, uuid); - if (dom) { - virObjectUnlock(dom); - dom = NULL; + if ((dom = virDomainObjListFindByUUID(driver->domains, uuid))) goto cleanup; - } if (!(dom = vzNewDomain(driver, name, uuid))) goto cleanup; -- 1.8.3.1

Free sdkdom on any result of prlsdkNewDomainByHandle. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index e7e9638..2f3f125 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -1653,10 +1653,9 @@ prlsdkLoadDomains(vzDriverPtr driver) pret = PrlResult_GetParamByIndex(result, i, &sdkdom); prlsdkCheckRetGoto(pret, error); - if (!(dom = prlsdkNewDomainByHandle(driver, sdkdom))) - continue; + if ((dom = prlsdkNewDomainByHandle(driver, sdkdom))) + virObjectUnlock(dom); - virObjectUnlock(dom); PrlHandle_Free(sdkdom); sdkdom = PRL_INVALID_HANDLE; } -- 1.8.3.1

Adding domain to domain list on preparation step is not correct. First domain is not fully constructed - domain definition is missing. Second we can't use VIR_MIGRATE_PARAM_DEST_XML parameter to parse definition as vz sdk can patch it by itself. Let's add/remove domain on finish step. This is for synchronization purpose only so domain is present/absent on destination after migration completion. Actually domain object will probably be created right after actual vz sdk migration start by vz sdk domain defined event. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 65 ++++++++++++++++++------------------------------------ src/vz/vz_sdk.c | 17 +++++++++++++- src/vz/vz_sdk.h | 5 +++++ 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index a404666..425d89a 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -2283,7 +2283,7 @@ vzDomainMigrateBegin3Params(virDomainPtr domain, if (!(dom = vzDomObjFromDomain(domain))) goto cleanup; - /* session uuid is for backward compat */ + /* session uuid, domain uuid and domain name are for backward compat */ if (vzBakeCookie(privconn->driver, dom, cookieout, cookieoutlen, VZ_MIGRATION_COOKIE_SESSION_UUID | VZ_MIGRATION_COOKIE_DOMAIN_UUID @@ -2328,8 +2328,8 @@ static int vzDomainMigratePrepare3Params(virConnectPtr conn, virTypedParameterPtr params, int nparams, - const char *cookiein, - int cookieinlen, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, char **cookieout, int *cookieoutlen, char **uri_out, @@ -2338,8 +2338,6 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, vzConnPtr privconn = conn->privateData; const char *miguri = NULL; const char *dname = NULL; - virDomainObjPtr dom = NULL; - vzMigrationCookiePtr mig = NULL; int ret = -1; virCheckFlags(VZ_MIGRATION_FLAGS, -1); @@ -2358,11 +2356,6 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, if (!miguri && !(*uri_out = vzMigrationCreateURI())) goto cleanup; - if (!(mig = vzEatCookie(cookiein, cookieinlen, - VZ_MIGRATION_COOKIE_DOMAIN_UUID - | VZ_MIGRATION_COOKIE_DOMAIN_NAME))) - goto cleanup; - /* domain uuid and domain name are for backward compat */ if (vzBakeCookie(privconn->driver, NULL, cookieout, cookieoutlen, @@ -2371,30 +2364,9 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, | VZ_MIGRATION_COOKIE_DOMAIN_NAME) < 0) goto cleanup; - virObjectLock(privconn->driver); - dom = virDomainObjListFindByUUID(privconn->driver->domains, mig->uuid); - if (dom) { - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(mig->uuid, uuidstr); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("A domain with uuid '%s' already exists"), - uuidstr); - goto unlock; - } - - if (!(dom = vzNewDomain(privconn->driver, - dname ? dname : mig->name, mig->uuid))) - goto unlock; - ret = 0; - unlock: - virObjectUnlock(privconn->driver); - cleanup: - vzMigrationCookieFree(mig); - if (dom) - virObjectUnlock(dom); return ret; } @@ -2639,29 +2611,32 @@ vzDomainMigrateFinish3Params(virConnectPtr dconn, vzConnPtr privconn = dconn->privateData; vzDriverPtr driver = privconn->driver; const char *name = NULL; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; virCheckFlags(VZ_MIGRATION_FLAGS, NULL); if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) - goto cleanup; + return NULL; if (virTypedParamsGetString(params, nparams, VIR_MIGRATE_PARAM_DEST_NAME, &name) < 0) - goto cleanup; - - if (!(dom = virDomainObjListFindByName(driver->domains, name))) { - virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching name '%s'"), name); - goto cleanup; - } + return NULL; if (cancelled) { + if (!(dom = virDomainObjListFindByName(driver->domains, name))) + return NULL; + virDomainObjListRemove(driver->domains, dom); - dom = NULL; - goto cleanup; + virObjectUnref(dom); + + return NULL; } - if (prlsdkLoadDomain(driver, dom)) + sdkdom = prlsdkSdkDomainLookupByName(driver, name); + if (sdkdom == PRL_INVALID_HANDLE) + goto cleanup; + + if (!(dom = prlsdkNewDomainByHandle(driver, sdkdom))) goto cleanup; domain = virGetDomain(dconn, dom->def->name, dom->def->uuid); @@ -2671,9 +2646,11 @@ vzDomainMigrateFinish3Params(virConnectPtr dconn, cleanup: /* In this situation we have to restore domain on source. But the migration * is already finished. */ - if (!cancelled && !domain) + if (!domain) VIR_WARN("Can't provide domain '%s' after successfull migration.", name); - virDomainObjEndAPI(&dom); + if (dom) + virObjectUnlock(dom); + PrlHandle_Free(sdkdom); return domain; } diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 2f3f125..72da66a 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -375,6 +375,21 @@ prlsdkSdkDomainLookupByUUID(vzDriverPtr driver, const unsigned char *uuid) return sdkdom; } +PRL_HANDLE +prlsdkSdkDomainLookupByName(vzDriverPtr driver, const char *name) +{ + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + + if (prlsdkSdkDomainLookup(driver, name, + PGVC_SEARCH_BY_NAME, &sdkdom) < 0) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), name); + return PRL_INVALID_HANDLE; + } + + return sdkdom; +} + static int prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid) { @@ -1243,7 +1258,7 @@ prlsdkConvertCpuMode(PRL_HANDLE sdkdom, virDomainDefPtr def) return -1; } -static virDomainObjPtr +virDomainObjPtr prlsdkNewDomainByHandle(vzDriverPtr driver, PRL_HANDLE sdkdom) { virDomainObjPtr dom = NULL; diff --git a/src/vz/vz_sdk.h b/src/vz/vz_sdk.h index f570560..75f66d6 100644 --- a/src/vz/vz_sdk.h +++ b/src/vz/vz_sdk.h @@ -93,3 +93,8 @@ prlsdkMigrate(virDomainObjPtr dom, const char unsigned *session_uuid, const char *dname, unsigned int flags); + +PRL_HANDLE +prlsdkSdkDomainLookupByName(vzDriverPtr driver, const char *name); +virDomainObjPtr +prlsdkNewDomainByHandle(vzDriverPtr driver, PRL_HANDLE sdkdom); -- 1.8.3.1

We need to issue domain undefine event on finish step if we removing domain from domain list as vz sdk event handler will not do it for us. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 425d89a..46c6b4b 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -2623,9 +2623,18 @@ vzDomainMigrateFinish3Params(virConnectPtr dconn, return NULL; if (cancelled) { + virObjectEventPtr event = NULL; + if (!(dom = virDomainObjListFindByName(driver->domains, name))) return NULL; + event = virDomainEventLifecycleNewFromObj(dom, + VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED); + + if (event) + virObjectEventStateQueue(driver->domainEventState, event); + virDomainObjListRemove(driver->domains, dom); virObjectUnref(dom); -- 1.8.3.1

We can not and should not sync domain cache on error path in finish step of migration. We can not as we really don't know what is the reason of cancelling and we should not as user should not make assumptions on state on error path. What we should do is cleaning up temporary migration state that is induced on prepare step but we don't have one. Thus cancellation should be noop. So, please, fixup 5th patch of series and this patch into 4th one. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index ae94d0b..9c93db1 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -2960,30 +2960,13 @@ vzDomainMigrateFinish3Params(virConnectPtr dconn, if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) return NULL; + if (cancelled) + return NULL; + if (virTypedParamsGetString(params, nparams, VIR_MIGRATE_PARAM_DEST_NAME, &name) < 0) return NULL; - if (cancelled) { - virObjectEventPtr event = NULL; - - if (!(dom = virDomainObjListFindByName(driver->domains, name))) - return NULL; - - event = virDomainEventLifecycleNewFromObj(dom, - VIR_DOMAIN_EVENT_UNDEFINED, - VIR_DOMAIN_EVENT_UNDEFINED_REMOVED); - - if (event) - virObjectEventStateQueue(driver->domainEventState, event); - - virDomainObjListRemove(driver->domains, dom); - virObjectUnref(dom); - - return NULL; - } - - if (!(dom = prlsdkAddDomainByName(driver, name))) goto cleanup; -- 1.8.3.1

08-Jun-16 10:17, Nikolay Shirokovskiy пишет:
Patch 4 is main one. Others are fixes and ground works.
Nikolay Shirokovskiy (5): vz: don't pass empty and unused fields in migration cookie vz: fix missed defined domain event vz: fix memory leaks in prlsdkLoadDomains vz: fix destination domain synchronization vz: issue domain undefined event on finish step if needed
src/vz/vz_driver.c | 175 ++++++++++++++++++++++++++++------------------------- src/vz/vz_sdk.c | 28 ++++++--- src/vz/vz_sdk.h | 5 ++ 3 files changed, 118 insertions(+), 90 deletions(-)
ACK and pushed now with suggested fixup. Thanks! Maxim
participants (2)
-
maxim nestratov
-
Nikolay Shirokovskiy