
@@ -39,13 +40,19 @@ struct _virNodeDeviceObj { };
struct _virNodeDeviceObjList { - size_t count; - virNodeDeviceObjPtr *objs; + virObjectLockable parent; + + /* name string -> virNodeDeviceObj mapping + * for O(1), lockless lookup-by-uuid */
I think you meant lookup-by-name ^here. More importantly though, I don't understand the comment at all, well I understand the words :), but the context is all noise - why should be the lookup lockless? You always lock the objlist prior to calling virHashLookup, followed by ref'ing and returning the result, I know we have that in other conf/vir*obj* modules and those don't make any more sense to me either.
+ virHashTable *objs; + };
static virClassPtr virNodeDeviceObjClass; +static virClassPtr virNodeDeviceObjListClass; static void virNodeDeviceObjDispose(void *opaque); +static void virNodeDeviceObjListDispose(void *opaque);
static int virNodeDeviceObjOnceInit(void) @@ -56,6 +63,12 @@ virNodeDeviceObjOnceInit(void) virNodeDeviceObjDispose))) return -1;
+ if (!(virNodeDeviceObjListClass = virClassNew(virClassForObjectLockable(), + "virNodeDeviceObjList", + sizeof(virNodeDeviceObjList), + virNodeDeviceObjListDispose))) + return -1; + return 0; }
@@ -211,26 +224,49 @@ virNodeDeviceFindVPORTCapDef(const virNodeDeviceObj *obj) }
+static int +virNodeDeviceObjListFindBySysfsPathCallback(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload; + virNodeDeviceDefPtr def;
I recall having discussed ^this with you already, but this is one-time use only and I simply don't think it's necessary, I'd use helper variables for the sole purpose of getting rid of multiple levels of dereference either in a multi-use situation, or the number of levels dereferenced makes the line really long and the usage unreadable. (this also occurs on multiple places...no need to repeat this...)
+ const char *sysfs_path = opaque; + int want = 0; + + virObjectLock(obj); + def = obj->def; + if (STREQ_NULLABLE(def->sysfs_path, sysfs_path)) + want = 1; + virObjectUnlock(obj); + return want; +} + + virNodeDeviceObjPtr virNodeDeviceObjListFindBySysfsPath(virNodeDeviceObjListPtr devs, const char *sysfs_path) { - size_t i; + virNodeDeviceObjPtr obj;
- for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virNodeDeviceDefPtr def; + virObjectLock(devs); + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindBySysfsPathCallback, + (void *)sysfs_path); + virObjectRef(obj); + virObjectUnlock(devs);
^This pattern occurs multiple times within the patch, I think it deserves a simple helper
+ if (obj) virObjectLock(obj); - def = obj->def; - if ((def->sysfs_path != NULL) && - (STREQ(def->sysfs_path, sysfs_path))) { - return virObjectRef(obj); - } - virObjectUnlock(obj); - }
- return NULL; + return obj; +} + + +static virNodeDeviceObjPtr +virNodeDeviceObjListFindByNameLocked(virNodeDeviceObjListPtr devs, + const char *name) +{ + return virObjectRef(virHashLookup(devs->objs, name)); }
@@ -238,20 +274,42 @@ virNodeDeviceObjPtr virNodeDeviceObjListFindByName(virNodeDeviceObjListPtr devs, const char *name) { - size_t i; - - for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virNodeDeviceDefPtr def; + virNodeDeviceObjPtr obj;
+ virObjectLock(devs); + obj = virNodeDeviceObjListFindByNameLocked(devs, name); + virObjectUnlock(devs); + if (obj) virObjectLock(obj); - def = obj->def; - if (STREQ(def->name, name)) - return virObjectRef(obj); - virObjectUnlock(obj); - }
- return NULL; + return obj; +} + + +struct virNodeDeviceObjListFindByWWNsData { + const char *parent_wwnn; + const char *parent_wwpn; +}; + +static int +virNodeDeviceObjListFindByWWNsCallback(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload; + struct virNodeDeviceObjListFindByWWNsData *data = + (struct virNodeDeviceObjListFindByWWNsData *) opaque; + virNodeDevCapsDefPtr cap; + int want = 0; + + virObjectLock(obj); + if ((cap = virNodeDeviceFindFCCapDef(obj)) && + STREQ_NULLABLE(cap->data.scsi_host.wwnn, data->parent_wwnn) && + STREQ_NULLABLE(cap->data.scsi_host.wwpn, data->parent_wwpn) && + virNodeDeviceFindVPORTCapDef(obj)) + want = 1; + virObjectUnlock(obj); + return want; }
@@ -260,22 +318,40 @@ virNodeDeviceObjListFindByWWNs(virNodeDeviceObjListPtr devs, const char *parent_wwnn, const char *parent_wwpn) { - size_t i; + virNodeDeviceObjPtr obj; + struct virNodeDeviceObjListFindByWWNsData data = { + .parent_wwnn = parent_wwnn, .parent_wwpn = parent_wwpn };
- for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virNodeDevCapsDefPtr cap; + virObjectLock(devs); + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindByWWNsCallback, + &data); + virObjectRef(obj); + virObjectUnlock(devs);
+ if (obj) virObjectLock(obj); - if ((cap = virNodeDeviceFindFCCapDef(obj)) && - STREQ_NULLABLE(cap->data.scsi_host.wwnn, parent_wwnn) && - STREQ_NULLABLE(cap->data.scsi_host.wwpn, parent_wwpn) && - virNodeDeviceFindVPORTCapDef(obj)) - return virObjectRef(obj); - virObjectUnlock(obj); - }
- return NULL; + return obj; +} + + +static int +virNodeDeviceObjListFindByFabricWWNCallback(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload; + const char *matchstr = opaque; + virNodeDevCapsDefPtr cap; + int want = 0; + + virObjectLock(obj); + if ((cap = virNodeDeviceFindFCCapDef(obj)) && + STREQ_NULLABLE(cap->data.scsi_host.fabric_wwn, matchstr) && + virNodeDeviceFindVPORTCapDef(obj)) + want = 1; + virObjectUnlock(obj); + return want; }
@@ -283,21 +359,35 @@ static virNodeDeviceObjPtr virNodeDeviceObjListFindByFabricWWN(virNodeDeviceObjListPtr devs, const char *parent_fabric_wwn) { - size_t i; + virNodeDeviceObjPtr obj;
- for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virNodeDevCapsDefPtr cap; + virObjectLock(devs); + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindByFabricWWNCallback, + (void *)parent_fabric_wwn); + virObjectRef(obj); + virObjectUnlock(devs);
+ if (obj) virObjectLock(obj); - if ((cap = virNodeDeviceFindFCCapDef(obj)) && - STREQ_NULLABLE(cap->data.scsi_host.fabric_wwn, parent_fabric_wwn) && - virNodeDeviceFindVPORTCapDef(obj)) - return virObjectRef(obj); - virObjectUnlock(obj); - }
- return NULL; + return obj; +} + + +static int +virNodeDeviceObjListFindByCapCallback(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload; + const char *matchstr = opaque; + int want = 0; + + virObjectLock(obj); + if (virNodeDeviceObjHasCap(obj, matchstr)) + want = 1; + virObjectUnlock(obj); + return want; }
@@ -305,18 +395,59 @@ static virNodeDeviceObjPtr virNodeDeviceObjListFindByCap(virNodeDeviceObjListPtr devs, const char *cap) { - size_t i; + virNodeDeviceObjPtr obj;
- for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; + virObjectLock(devs); + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindByCapCallback, + (void *)cap); + virObjectRef(obj); + virObjectUnlock(devs);
+ if (obj) virObjectLock(obj); - if (virNodeDeviceObjHasCap(obj, cap)) - return virObjectRef(obj); - virObjectUnlock(obj); - }
- return NULL; + return obj; +} + + +struct virNodeDeviceObjListFindSCSIHostByWWNsData { + const char *wwnn; + const char *wwpn; +}; + +static int +virNodeDeviceObjListFindSCSIHostByWWNsCallback(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload; + virNodeDeviceDefPtr def; + struct virNodeDeviceObjListFindSCSIHostByWWNsData *data = + (struct virNodeDeviceObjListFindSCSIHostByWWNsData *) opaque; + virNodeDevCapsDefPtr cap; + int want = 0; + + virObjectLock(obj); + def = obj->def; + cap = def->caps; + + while (cap) { + if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { + virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); + if (cap->data.scsi_host.flags & + VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { + if (STREQ(cap->data.scsi_host.wwnn, data->wwnn) && + STREQ(cap->data.scsi_host.wwpn, data->wwpn)) { + want = 1; + break; + } + } + } + cap = cap->next; + } + + virObjectUnlock(obj); + return want; }
@@ -325,31 +456,30 @@ virNodeDeviceObjListFindSCSIHostByWWNs(virNodeDeviceObjListPtr devs, const char *wwnn, const char *wwpn) { - size_t i; + virNodeDeviceObjPtr obj; + struct virNodeDeviceObjListFindSCSIHostByWWNsData data = { + .wwnn = wwnn, .wwpn = wwpn };
- for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virNodeDevCapsDefPtr cap; + virObjectLock(devs); + obj = virHashSearch(devs->objs, + virNodeDeviceObjListFindSCSIHostByWWNsCallback, + &data); + virObjectRef(obj); + virObjectUnlock(devs);
+ if (obj) virObjectLock(obj); - cap = obj->def->caps; - - while (cap) { - if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { - virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); - if (cap->data.scsi_host.flags & - VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { - if (STREQ(cap->data.scsi_host.wwnn, wwnn) && - STREQ(cap->data.scsi_host.wwpn, wwpn)) - return virObjectRef(obj); - } - } - cap = cap->next; - } - virObjectUnlock(obj); - }
- return NULL; + return obj; +} + + +static void +virNodeDeviceObjListDispose(void *obj) +{ + virNodeDeviceObjListPtr devs = obj; + + virHashFree(devs->objs); }
@@ -358,8 +488,17 @@ virNodeDeviceObjListNew(void) { virNodeDeviceObjListPtr devs;
- if (VIR_ALLOC(devs) < 0) + if (virNodeDeviceObjInitialize() < 0) + return NULL; + + if (!(devs = virObjectLockableNew(virNodeDeviceObjListClass))) return NULL; + + if (!(devs->objs = virHashCreate(50, virObjectFreeHashData))) { + virObjectUnref(devs); + return NULL; + } + return devs; }
@@ -367,11 +506,7 @@ virNodeDeviceObjListNew(void) void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs) { - size_t i; - for (i = 0; i < devs->count; i++) - virObjectUnref(devs->objs[i]); - VIR_FREE(devs->objs); - VIR_FREE(devs); + virObjectUnref(devs); }
@@ -381,22 +516,28 @@ virNodeDeviceObjListAssignDef(virNodeDeviceObjListPtr devs, { virNodeDeviceObjPtr obj;
- if ((obj = virNodeDeviceObjListFindByName(devs, def->name))) { + virObjectLock(devs); + + if ((obj = virNodeDeviceObjListFindByNameLocked(devs, def->name))) { + virObjectLock(obj); virNodeDeviceDefFree(obj->def); obj->def = def; - return obj; - } + } else { + if (!(obj = virNodeDeviceObjNew())) + goto cleanup;
- if (!(obj = virNodeDeviceObjNew())) - return NULL; + if (virHashAddEntry(devs->objs, def->name, obj) < 0) { + virNodeDeviceObjEndAPI(&obj); + goto cleanup; + }
- if (VIR_APPEND_ELEMENT_COPY(devs->objs, devs->count, obj) < 0) { - virNodeDeviceObjEndAPI(&obj); - return NULL; + obj->def = def; + virObjectRef(obj); } - obj->def = def;
- return virObjectRef(obj); + cleanup: + virObjectUnlock(devs); + return obj; }
@@ -404,21 +545,20 @@ void virNodeDeviceObjListRemove(virNodeDeviceObjListPtr devs, virNodeDeviceObjPtr obj) { - size_t i; - - virObjectUnlock(obj); + virNodeDeviceDefPtr def;
- for (i = 0; i < devs->count; i++) { - virObjectLock(devs->objs[i]); - if (devs->objs[i] == obj) { - virObjectUnlock(devs->objs[i]); - virObjectUnref(devs->objs[i]); + if (!obj) + return; + def = obj->def;
In this specific case, what's the benefit of having @def...
- VIR_DELETE_ELEMENT(devs->objs, i, devs->count); - break; - } - virObjectUnlock(devs->objs[i]); - } + virObjectRef(obj); + virObjectUnlock(obj); + virObjectLock(devs); + virObjectLock(obj); + virHashRemoveEntry(devs->objs, def->name);
...and use it here instead of obj->def->name... I'd prefer if you just dropped it here.
+ virObjectUnlock(obj); + virObjectUnref(obj); + virObjectUnlock(devs); }
@@ -643,25 +783,89 @@ virNodeDeviceCapMatch(virNodeDeviceObjPtr obj, }
+struct virNodeDeviceCountData { + virConnectPtr conn; + virNodeDeviceObjListFilter aclfilter; + const char *matchstr; + int count; +};
These single purpose structures often have the same members across multiple callbacks, I was wondering whether we could just make one generic one, call it virNodeDeviceQueryData. But then, it would unnecessarily big, most fields would be unused, I don't know, it might not be a "nicer" solution eventually, so I'm ambivalent on this... Erik