From: Shaju Abraham <shaju.abraham(a)nutanix.com>
Libvirt assumes that there will ever be only one VM in a host
with a specific UUId and name. The VM object pointers are stored in
hash tables and are indexed using the UUID or name. For local migrations
both the source and destination VMs reside on the same host and share
the same name and UUID. This will introduce hash collisions. Introduce
two more hash tables to manage the destination VM object. The remote VM
objects are always stored in the newly introduced remote hashtable. The
hash table helper routines are modified to handle the newly introduced
remote hash tables.
The existing functions are duplicated to operate on the remote hash table.
This is done intentionally so that the changes to existing migration framework
is minimal.
Signed-off-by: Shaju Abraham <shaju.abraham(a)nutanix.com>
---
src/conf/virdomainobjlist.c | 232 ++++++++++++++++++++++++++++++++++--
src/conf/virdomainobjlist.h | 10 ++
src/libvirt_private.syms | 4 +
3 files changed, 238 insertions(+), 8 deletions(-)
diff --git a/src/conf/virdomainobjlist.c b/src/conf/virdomainobjlist.c
index 417025ae9f..37fc0c4d5e 100644
--- a/src/conf/virdomainobjlist.c
+++ b/src/conf/virdomainobjlist.c
@@ -48,10 +48,14 @@ struct _virDomainObjList {
/* uuid string -> virDomainObj mapping
* for O(1), lockless lookup-by-uuid */
virHashTable *objs;
+ /* Hashtable to support Local Migration */
+ virHashTable *remote_objs;
/* name -> virDomainObj mapping for O(1),
* lockless lookup-by-name */
virHashTable *objsName;
+ /* Hashtable to support Local Migration */
+ virHashTable *remote_objsName;
};
@@ -80,6 +84,13 @@ virDomainObjListPtr virDomainObjListNew(void)
virObjectUnref(doms);
return NULL;
}
+ if (!(doms->remote_objs = virHashCreate(50, virObjectFreeHashData)) ||
+ !(doms->remote_objsName = virHashCreate(50, virObjectFreeHashData))) {
+ virHashFree(doms->objs);
+ virHashFree(doms->objsName);
+ virObjectUnref(doms);
+ return NULL;
+ }
return doms;
}
@@ -92,6 +103,193 @@ static void virDomainObjListDispose(void *obj)
virHashFree(doms->objs);
virHashFree(doms->objsName);
}
+/*Remote Hash table manipulation routines*/
+static virDomainObjPtr
+virDomainObjListFindByUUIDRemoteLocked(virDomainObjListPtr doms,
+ const unsigned char *uuid)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDomainObjPtr obj;
+
+ virUUIDFormat(uuid, uuidstr);
+ obj = virHashLookup(doms->remote_objs, uuidstr);
+ virObjectRef(obj);
+ if (obj) {
+ virObjectLock(obj);
+ if (obj->removing) {
+ virObjectUnlock(obj);
+ virObjectUnref(obj);
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+static virDomainObjPtr
+virDomainObjListFindByUUIDFromHashLocked(virHashTable *table,
+ const unsigned char *uuid)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDomainObjPtr obj;
+
+ virUUIDFormat(uuid, uuidstr);
+ obj = virHashLookup(table, uuidstr);
+ virObjectRef(obj);
+ if (obj) {
+ virObjectLock(obj);
+ if (obj->removing) {
+ virObjectUnlock(obj);
+ virObjectUnref(obj);
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+/**
+ * @doms: Domain object list
+ * @uuid: UUID to search the doms->objs table
+ *
+ * Lookup the @uuid in the doms->objs hash table and return a
+ * locked and ref counted domain object if found. Caller is
+ * expected to use the virDomainObjEndAPI when done with the object.
+ */
+virDomainObjPtr
+virDomainObjListFindByUUIDRemote(virDomainObjListPtr doms,
+ const unsigned char *uuid)
+{
+ virDomainObjPtr obj;
+ virObjectRWLockRead(doms);
+ obj = virDomainObjListFindByUUIDRemoteLocked(doms, uuid);
+ virObjectRWUnlock(doms);
+
+ return obj;
+}
+static virDomainObjPtr
+virDomainObjListFindByNameFromHashLocked(virHashTable *table,
+ const char *name)
+{
+ virDomainObjPtr obj;
+
+ obj = virHashLookup(table, name);
+ virObjectRef(obj);
+ if (obj) {
+ virObjectLock(obj);
+ if (obj->removing) {
+ virObjectUnlock(obj);
+ virObjectUnref(obj);
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+/**
+ * @doms: Domain object list
+ * @name: Name to search the doms->objsName table
+ *
+ * Lookup the @name in the doms->objsName_remote hash table and return a
+ * locked and ref counted domain object if found. Caller is expected
+ * to use the virDomainObjEndAPI when done with the object.
+ */
+virDomainObjPtr
+virDomainObjListFindByNameRemote(virDomainObjListPtr doms,
+ const char *name)
+{
+ virDomainObjPtr obj;
+ virObjectRWLockRead(doms);
+ obj = virDomainObjListFindByNameFromHashLocked(doms->remote_objs, name);
+ virObjectRWUnlock(doms);
+
+ return obj;
+}
+
+/* The caller must hold lock on 'doms' in addition to
'virDomainObjListRemove'
+ * requirements
+ *
+ * Can be used to remove current element while iterating with
+ * virDomainObjListForEach
+ */
+int
+virDomainObjListRemoveRemoteLocked(virDomainObjListPtr doms,
+ virDomainObjPtr dom)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDomainObjPtr remoteDom;
+ int ret = -1;
+
+ virUUIDFormat(dom->def->uuid, uuidstr);
+ remoteDom = virHashSteal(doms->remote_objs, uuidstr);
+ if (remoteDom != dom) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Can't get matching VM from uuid"));
+ return ret;
+ }
+ remoteDom = virHashSteal(doms->remote_objsName, dom->def->name);
+ if (remoteDom != dom) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Can't get matching VM from name"));
+ return ret;
+ }
+ return 0;
+}
+
+/**
+ * @doms: Pointer to the domain object list
+ * @dom: Domain pointer from either after Add or FindBy* API where the
+ * @dom was successfully added to both the doms->objs and ->objsName
+ * hash tables that now would need to be removed.
+ *
+ * The caller must hold a lock on the driver owning 'doms',
+ * and must also have locked and ref counted 'dom', to ensure
+ * no one else is either waiting for 'dom' or still using it.
+ *
+ * When this function returns, @dom will be removed from the hash
+ * tables and returned with lock and refcnt that was present upon entry.
+ */
+int
+virDomainObjListRemoveRemote(virDomainObjListPtr doms,
+ virDomainObjPtr dom)
+{
+ int ret = -1;
+ virObjectRef(dom);
+ virObjectUnlock(dom);
+ virObjectRWLockWrite(doms);
+ virObjectLock(dom);
+ ret = virDomainObjListRemoveRemoteLocked(doms, dom);
+ virObjectUnref(dom);
+ virObjectRWUnlock(doms);
+ return ret;
+}
+/*
+ * @doms: Pointer to the domain object list
+ * @dom: Domain pointer
+ * This helper routine inserts a domain object to the hash tables.
+ * @dom should be successfully added to both the doms->objs and ->objsName
+ * hashtables. Required by the local migration use case.
+*/
+int virDomainObjListAddEntry(virDomainObjListPtr doms, virDomainObjPtr dom)
+{
+ int ret = -1;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->def->uuid, uuidstr);
+ virObjectRef(dom);
+ virObjectUnlock(dom);
+ virObjectLock(doms);
+ virObjectLock(dom);
+ if (virHashAddEntry(doms->objs, uuidstr, dom) < 0) {
+ virObjectUnref(dom);
+ return ret;
+ }
+ if (virHashAddEntry(doms->objsName, dom->def->name, dom) < 0) {
+ virHashRemoveEntry(doms->objs, uuidstr);
+ goto cleanup;
+ }
+ ret = 0;
+ cleanup:
+ virObjectUnlock(dom);
+ virObjectUnlock(doms);
+ return ret;
+}
static int virDomainObjListSearchID(const void *payload,
@@ -225,6 +423,7 @@ virDomainObjListFindByName(virDomainObjListPtr doms,
/**
* @doms: Domain object list pointer
* @vm: Domain object to be added
+ * @localMigration: flag to indicate local migration
*
* Upon entry @vm should have at least 1 ref and be locked.
*
@@ -240,16 +439,22 @@ virDomainObjListFindByName(virDomainObjListPtr doms,
*/
static int
virDomainObjListAddObjLocked(virDomainObjListPtr doms,
- virDomainObjPtr vm)
+ virDomainObjPtr vm, bool localMigration)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virHashTable *table = doms->objs;
+ virHashTable *table_name = doms->objsName;
+ if (localMigration) {
+ table = doms->remote_objs;
+ table_name = doms->remote_objsName;
+ }
virUUIDFormat(vm->def->uuid, uuidstr);
- if (virHashAddEntry(doms->objs, uuidstr, vm) < 0)
+ if (virHashAddEntry(table, uuidstr, vm) < 0)
return -1;
virObjectRef(vm);
- if (virHashAddEntry(doms->objsName, vm->def->name, vm) < 0) {
+ if (virHashAddEntry(table_name, vm->def->name, vm) < 0) {
virHashRemoveEntry(doms->objs, uuidstr);
return -1;
}
@@ -281,14 +486,25 @@ virDomainObjListAddLocked(virDomainObjListPtr doms,
unsigned int flags,
virDomainDefPtr *oldDef)
{
- virDomainObjPtr vm;
+ virDomainObjPtr vm = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
+ bool localMigration = 0;
+ virHashTable *table = doms->objs;
+ virHashTable *table_name = doms->objsName;
if (oldDef)
*oldDef = NULL;
+ /* Check if it is local migration. In that case the src vm exists with
+ * same UUID and name.We have to create a new UUID and name for the domain.
+ */
+ if (flags & VIR_DOMAIN_OBJ_LIST_ADD_LIVE_LOCAL) {
+ table = doms->remote_objs;
+ table_name = doms->remote_objsName;
+ localMigration = 1;
+ }
/* See if a VM with matching UUID already exists */
- if ((vm = virDomainObjListFindByUUIDLocked(doms, def->uuid))) {
+ if ((vm = virDomainObjListFindByUUIDFromHashLocked(table, def->uuid))) {
if (vm->removing) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("domain '%s' is already being removed"),
@@ -325,7 +541,7 @@ virDomainObjListAddLocked(virDomainObjListPtr doms,
oldDef);
} else {
/* UUID does not match, but if a name matches, refuse it */
- if ((vm = virDomainObjListFindByNameLocked(doms, def->name))) {
+ if ((vm = virDomainObjListFindByNameFromHashLocked(table_name, def->name))) {
virUUIDFormat(vm->def->uuid, uuidstr);
virReportError(VIR_ERR_OPERATION_FAILED,
_("domain '%s' already exists with uuid
%s"),
@@ -337,7 +553,7 @@ virDomainObjListAddLocked(virDomainObjListPtr doms,
goto error;
vm->def = def;
- if (virDomainObjListAddObjLocked(doms, vm) < 0) {
+ if (virDomainObjListAddObjLocked(doms, vm, localMigration) < 0) {
vm->def = NULL;
goto error;
}
@@ -563,7 +779,7 @@ virDomainObjListLoadStatus(virDomainObjListPtr doms,
goto error;
}
- if (virDomainObjListAddObjLocked(doms, obj) < 0)
+ if (virDomainObjListAddObjLocked(doms, obj, 0) < 0)
goto error;
if (notify)
diff --git a/src/conf/virdomainobjlist.h b/src/conf/virdomainobjlist.h
index 6150e13aa4..a3253787ff 100644
--- a/src/conf/virdomainobjlist.h
+++ b/src/conf/virdomainobjlist.h
@@ -33,12 +33,18 @@ virDomainObjPtr virDomainObjListFindByID(virDomainObjListPtr doms,
int id);
virDomainObjPtr virDomainObjListFindByUUID(virDomainObjListPtr doms,
const unsigned char *uuid);
+virDomainObjPtr virDomainObjListFindByUUIDRemote(virDomainObjListPtr doms,
+ const unsigned char *uuid);
virDomainObjPtr virDomainObjListFindByName(virDomainObjListPtr doms,
const char *name);
+virDomainObjPtr virDomainObjListFindByNameRemote(virDomainObjListPtr doms,
+ const char *name);
+int virDomainObjListAddEntry(virDomainObjListPtr doms,virDomainObjPtr dom);
enum {
VIR_DOMAIN_OBJ_LIST_ADD_LIVE = (1 << 0),
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE = (1 << 1),
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE_LOCAL = (1 << 2),
};
virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
virDomainDefPtr def,
@@ -61,6 +67,10 @@ void virDomainObjListRemove(virDomainObjListPtr doms,
virDomainObjPtr dom);
void virDomainObjListRemoveLocked(virDomainObjListPtr doms,
virDomainObjPtr dom);
+int virDomainObjListRemoveRemoteLocked(virDomainObjListPtr doms,
+ virDomainObjPtr dom);
+int virDomainObjListRemoveRemote(virDomainObjListPtr doms,
+ virDomainObjPtr dom);
int virDomainObjListLoadAllConfigs(virDomainObjListPtr doms,
const char *configDir,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 970f412527..c104313319 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1045,7 +1045,9 @@ virDomainObjListConvert;
virDomainObjListExport;
virDomainObjListFindByID;
virDomainObjListFindByName;
+virDomainObjListFindByNameRemote;
virDomainObjListFindByUUID;
+virDomainObjListFindByUUIDRemote;
virDomainObjListForEach;
virDomainObjListGetActiveIDs;
virDomainObjListGetInactiveNames;
@@ -1054,7 +1056,9 @@ virDomainObjListNew;
virDomainObjListNumOfDomains;
virDomainObjListRemove;
virDomainObjListRemoveLocked;
+virDomainObjListRemoveRemote;
virDomainObjListRename;
+virDomainObjListAddEntry;
# conf/virdomainsnapshotobjlist.h
--
2.24.1