[libvirt] [PATCH v6 0/4] Make virNodeDeviceObj and virNodeDeviceObjList private

NB: Like v5, keeping same title for consistency v5: https://www.redhat.com/archives/libvir-list/2017-July/msg00610.html Changes since v5: * Replace patch 1 w/ the aha moment from review. The deletion API's don't need to use virNodeDeviceObjListGetParentHost. Instead they can just use virNodeDeviceObjListFindByName as the parent_wwnn/wwpn and parent_fabric_wwn are not stored in the vHBA. They're merely for the purpose of creation. The vHBA *does* store the def->parent by name and we can use that instead * Add patch 2 in order to remove the CREATE_DEVICE boolean from virNodeDeviceObjListGetParentHost as it won't be necessary since the only consumers are now CreateXML callers * Modify patch 3 calls to virHashSearch to add a NULL parameter since commit '38e516a52' added this (a real buzzkill for other changes too) * Modify patch 4 to include removing the locks in Nodedev calls for test_driver as well. John Ferlan (4): nodedev: Alter node device deletion logic nodedev: Remove @create from virNodeDeviceObjListGetParentHost nodedev: Convert virNodeDeviceObjListPtr to use hash tables nodedev: Remove driver locks around object list mgmt code src/conf/virnodedeviceobj.c | 580 ++++++++++++++++++++++++----------- src/conf/virnodedeviceobj.h | 3 +- src/node_device/node_device_driver.c | 90 ++---- src/node_device/node_device_hal.c | 16 +- src/node_device/node_device_udev.c | 13 +- src/test/test_driver.c | 53 ++-- 6 files changed, 459 insertions(+), 296 deletions(-) -- 2.9.4

Alter the node device deletion logic to make use of the parent field from the obj->def rather than call virNodeDeviceObjListGetParentHost. As it turns out the saved @def won't have parent_wwnn/wwpn or parent_fabric_wwn, so the only logical path would be to call virNodeDeviceObjListGetParentHostByParent which we can accomplish directly via virNodeDeviceObjListFindByName. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/node_device/node_device_driver.c | 26 +++++++++++++++++++------- src/test/test_driver.c | 26 +++++++++++++------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 0a19908..f56ff34 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -594,8 +594,9 @@ nodeDeviceDestroy(virNodeDevicePtr device) int ret = -1; virNodeDeviceObjPtr obj = NULL; virNodeDeviceDefPtr def; + char *parent = NULL; char *wwnn = NULL, *wwpn = NULL; - int parent_host = -1; + unsigned int parent_host; if (!(obj = nodeDeviceObjFindByName(device->name))) return -1; @@ -609,13 +610,23 @@ nodeDeviceDestroy(virNodeDevicePtr device) if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) < 0) goto cleanup; - /* virNodeDeviceGetParentHost will cause the device object's lock - * to be taken, so grab the object def which will have the various - * fields used to search (name, parent, parent_wwnn, parent_wwpn, - * or parent_fabric_wwn) and drop the object lock. */ + /* Because we're about to release the lock and thus run into a race + * possibility (however improbable) with a udevAddOneDevice change + * event which would essentially free the existing @def (obj->def) and + * replace it with something new, we need to grab the parent field + * and then find the parent obj in order to manage the vport */ + if (VIR_STRDUP(parent, def->parent) < 0) + goto cleanup; + virNodeDeviceObjEndAPI(&obj); - if ((parent_host = virNodeDeviceObjListGetParentHost(driver->devs, def, - EXISTING_DEVICE)) < 0) + + if (!(obj = virNodeDeviceObjListFindByName(driver->devs, parent))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find parent '%s' definition"), parent); + goto cleanup; + } + + if (virSCSIHostGetNumber(parent, &parent_host) < 0) goto cleanup; if (virVHBAManageVport(parent_host, wwpn, wwnn, VPORT_DELETE) < 0) @@ -626,6 +637,7 @@ nodeDeviceDestroy(virNodeDevicePtr device) cleanup: nodeDeviceUnlock(); virNodeDeviceObjEndAPI(&obj); + VIR_FREE(parent); VIR_FREE(wwnn); VIR_FREE(wwpn); return ret; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 83ab9cc..076b17a 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5618,8 +5618,9 @@ testNodeDeviceDestroy(virNodeDevicePtr dev) int ret = 0; testDriverPtr driver = dev->conn->privateData; virNodeDeviceObjPtr obj = NULL; + virNodeDeviceObjPtr parentobj = NULL; virNodeDeviceDefPtr def; - char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL; + char *wwnn = NULL, *wwpn = NULL; virObjectEventPtr event = NULL; if (!(obj = testNodeDeviceObjFindByName(driver, dev->name))) @@ -5629,22 +5630,22 @@ testNodeDeviceDestroy(virNodeDevicePtr dev) if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1) goto cleanup; - if (VIR_STRDUP(parent_name, def->parent) < 0) - goto cleanup; - - /* virNodeDeviceGetParentHost will cause the device object's lock to be - * taken, so we have to dup the parent's name and drop the lock - * before calling it. We don't need the reference to the object - * any more once we have the parent's name. */ + /* Unlike the real code we cannot run into the udevAddOneDevice race + * which would replace obj->def, so no need to save off the parent, + * but do need to drop the @obj lock so that the FindByName code doesn't + * deadlock on ourselves */ virObjectUnlock(obj); - /* We do this just for basic validation, but also avoid finding a - * vport capable HBA if for some reason our vHBA doesn't exist */ - if (virNodeDeviceObjListGetParentHost(driver->devs, def, - EXISTING_DEVICE) < 0) { + /* We do this just for basic validation and throw away the parentobj + * since there's no vport_delete to be run */ + if (!(parentobj = virNodeDeviceObjListFindByName(driver->devs, + def->parent))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find parent '%s' definition"), def->parent); virObjectLock(obj); goto cleanup; } + virNodeDeviceObjEndAPI(&parentobj); event = virNodeDeviceEventLifecycleNew(dev->name, VIR_NODE_DEVICE_EVENT_DELETED, @@ -5658,7 +5659,6 @@ testNodeDeviceDestroy(virNodeDevicePtr dev) cleanup: virNodeDeviceObjEndAPI(&obj); testObjectEventQueue(driver, event); - VIR_FREE(parent_name); VIR_FREE(wwnn); VIR_FREE(wwpn); return ret; -- 2.9.4

The only callers to this function are from CreateXML paths now, so let's just remove the unnecessary parameter. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/conf/virnodedeviceobj.c | 5 ++--- src/conf/virnodedeviceobj.h | 3 +-- src/node_device/node_device_driver.c | 3 +-- src/test/test_driver.c | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 4c5ee8c..035a56d 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -545,8 +545,7 @@ virNodeDeviceObjListFindVportParentHost(virNodeDeviceObjListPtr devs) int virNodeDeviceObjListGetParentHost(virNodeDeviceObjListPtr devs, - virNodeDeviceDefPtr def, - int create) + virNodeDeviceDefPtr def) { int parent_host = -1; @@ -561,7 +560,7 @@ virNodeDeviceObjListGetParentHost(virNodeDeviceObjListPtr devs, parent_host = virNodeDeviceObjListGetParentHostByFabricWWN(devs, def->name, def->parent_fabric_wwn); - } else if (create == CREATE_DEVICE) { + } else { /* Try to find a vport capable scsi_host when no parent supplied */ parent_host = virNodeDeviceObjListFindVportParentHost(devs); } diff --git a/src/conf/virnodedeviceobj.h b/src/conf/virnodedeviceobj.h index 788fb66..06f2e9e 100644 --- a/src/conf/virnodedeviceobj.h +++ b/src/conf/virnodedeviceobj.h @@ -75,8 +75,7 @@ virNodeDeviceObjListRemove(virNodeDeviceObjListPtr devs, int virNodeDeviceObjListGetParentHost(virNodeDeviceObjListPtr devs, - virNodeDeviceDefPtr def, - int create); + virNodeDeviceDefPtr def); virNodeDeviceObjListPtr virNodeDeviceObjListNew(void); diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index f56ff34..920d877 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -563,8 +563,7 @@ nodeDeviceCreateXML(virConnectPtr conn, if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1) goto cleanup; - if ((parent_host = virNodeDeviceObjListGetParentHost(driver->devs, def, - CREATE_DEVICE)) < 0) + if ((parent_host = virNodeDeviceObjListGetParentHost(driver->devs, def)) < 0) goto cleanup; if (virVHBAManageVport(parent_host, wwpn, wwnn, VPORT_CREATE) < 0) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 076b17a..bb2e7ba 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5580,7 +5580,7 @@ testNodeDeviceCreateXML(virConnectPtr conn, /* Unlike the "real" code we don't need the parent_host in order to * call virVHBAManageVport, but still let's make sure the code finds * something valid and no one messed up the mock environment. */ - if (virNodeDeviceObjListGetParentHost(driver->devs, def, CREATE_DEVICE) < 0) + if (virNodeDeviceObjListGetParentHost(driver->devs, def) < 0) goto cleanup; /* In the real code, we'd call virVHBAManageVport followed by -- 2.9.4

Rather than use a forward linked list of elements, it'll be much more efficient to use a hash table to reference the elements by unique name and to perform hash searches. This patch does all the heavy lifting of converting the list object to use a self locking list that contains the hash table. Each of the FindBy functions that do not involve finding the object by it's key (name) is converted to use virHashSearch in order to find the specific object. When searching for the key (name), it's possible to use virHashLookup. For any of the list perusal functions that are required to evaluate each object, the virHashForEach function is used. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/conf/virnodedeviceobj.c | 575 ++++++++++++++++++++++++++++++-------------- 1 file changed, 400 insertions(+), 175 deletions(-) diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 035a56d..58481e7 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -25,6 +25,7 @@ #include "viralloc.h" #include "virnodedeviceobj.h" #include "virerror.h" +#include "virhash.h" #include "virlog.h" #include "virstring.h" @@ -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 */ + 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; + 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, NULL); + virObjectRef(obj); + virObjectUnlock(devs); + 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, NULL); + 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, NULL); + 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, NULL); + 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, NULL); + 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; - 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); + virObjectUnlock(obj); + virObjectUnref(obj); + virObjectUnlock(devs); } @@ -619,25 +759,89 @@ virNodeDeviceCapMatch(virNodeDeviceObjPtr obj, } +struct virNodeDeviceCountData { + virConnectPtr conn; + virNodeDeviceObjListFilter aclfilter; + const char *matchstr; + int count; +}; + +static int +virNodeDeviceObjListNumOfDevicesCallback(void *payload, + const void *name ATTRIBUTE_UNUSED, + void *opaque) +{ + virNodeDeviceObjPtr obj = payload; + virNodeDeviceDefPtr def; + struct virNodeDeviceCountData *data = opaque; + virNodeDeviceObjListFilter aclfilter = data->aclfilter; + + virObjectLock(obj); + def = obj->def; + if ((!aclfilter || aclfilter(data->conn, def)) && + (!data->matchstr || virNodeDeviceObjHasCap(obj, data->matchstr))) + data->count++; + + virObjectUnlock(obj); + return 0; +} + + int virNodeDeviceObjListNumOfDevices(virNodeDeviceObjListPtr devs, virConnectPtr conn, const char *cap, virNodeDeviceObjListFilter aclfilter) { - size_t i; - int ndevs = 0; + struct virNodeDeviceCountData data = { + .conn = conn, .aclfilter = aclfilter, .matchstr = cap, .count = 0 }; - for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virObjectLock(obj); - if ((!aclfilter || aclfilter(conn, obj->def)) && - (!cap || virNodeDeviceObjHasCap(obj, cap))) - ++ndevs; - virObjectUnlock(obj); - } + virObjectLock(devs); + virHashForEach(devs->objs, virNodeDeviceObjListNumOfDevicesCallback, &data); + virObjectUnlock(devs); + + return data.count; +} + + +struct virNodeDeviceGetNamesData { + virConnectPtr conn; + virNodeDeviceObjListFilter aclfilter; + const char *matchstr; + int nnames; + char **names; + int maxnames; + bool error; +}; + +static int +virNodeDeviceObjListGetNamesCallback(void *payload, + const void *name ATTRIBUTE_UNUSED, + void *opaque) +{ + virNodeDeviceObjPtr obj = payload; + virNodeDeviceDefPtr def; + struct virNodeDeviceGetNamesData *data = opaque; + virNodeDeviceObjListFilter aclfilter = data->aclfilter; + + if (data->error) + return 0; - return ndevs; + virObjectLock(obj); + def = obj->def; + + if ((!aclfilter || aclfilter(data->conn, def)) && + (!data->matchstr || virNodeDeviceObjHasCap(obj, data->matchstr))) { + if (VIR_STRDUP(data->names[data->nnames], def->name) < 0) { + data->error = true; + goto cleanup; + } + data->nnames++; + } + + cleanup: + virObjectUnlock(obj); + return 0; } @@ -649,28 +853,22 @@ virNodeDeviceObjListGetNames(virNodeDeviceObjListPtr devs, char **const names, int maxnames) { - int nnames = 0; - size_t i; + struct virNodeDeviceGetNamesData data = { + .conn = conn, .aclfilter = aclfilter, .matchstr = cap, .names = names, + .nnames = 0, .maxnames = maxnames, .error = false }; - for (i = 0; i < devs->count && nnames < maxnames; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virObjectLock(obj); - if ((!aclfilter || aclfilter(conn, obj->def)) && - (!cap || virNodeDeviceObjHasCap(obj, cap))) { - if (VIR_STRDUP(names[nnames], obj->def->name) < 0) { - virObjectUnlock(obj); - goto failure; - } - nnames++; - } - virObjectUnlock(obj); - } + virObjectLock(devs); + virHashForEach(devs->objs, virNodeDeviceObjListGetNamesCallback, &data); + virObjectUnlock(devs); + + if (data.error) + goto error; - return nnames; + return data.nnames; - failure: - while (--nnames >= 0) - VIR_FREE(names[nnames]); + error: + while (--data.nnames) + VIR_FREE(data.names[data.nnames]); return -1; } @@ -707,6 +905,51 @@ virNodeDeviceMatch(virNodeDeviceObjPtr obj, #undef MATCH +struct virNodeDeviceObjListExportData { + virConnectPtr conn; + virNodeDeviceObjListFilter aclfilter; + unsigned int flags; + virNodeDevicePtr *devices; + int ndevices; + bool error; +}; + +static int +virNodeDeviceObjListExportCallback(void *payload, + const void *name ATTRIBUTE_UNUSED, + void *opaque) +{ + virNodeDeviceObjPtr obj = payload; + virNodeDeviceDefPtr def; + struct virNodeDeviceObjListExportData *data = opaque; + virNodeDevicePtr device = NULL; + + if (data->error) + return 0; + + virObjectLock(obj); + def = obj->def; + + if ((!data->aclfilter || data->aclfilter(data->conn, def)) && + virNodeDeviceMatch(obj, data->flags)) { + if (data->devices) { + if (!(device = virGetNodeDevice(data->conn, def->name)) || + VIR_STRDUP(device->parent, def->parent) < 0) { + virObjectUnref(device); + data->error = true; + goto cleanup; + } + data->devices[data->ndevices] = device; + } + data->ndevices++; + } + + cleanup: + virObjectUnlock(obj); + return 0; +} + + int virNodeDeviceObjListExport(virConnectPtr conn, virNodeDeviceObjListPtr devs, @@ -714,49 +957,31 @@ virNodeDeviceObjListExport(virConnectPtr conn, virNodeDeviceObjListFilter aclfilter, unsigned int flags) { - virNodeDevicePtr *tmp_devices = NULL; - virNodeDevicePtr device = NULL; - int ndevices = 0; - int ret = -1; - size_t i; + struct virNodeDeviceObjListExportData data = { + .conn = conn, .aclfilter = aclfilter, .flags = flags, + .devices = NULL, .ndevices = 0, .error = false }; + + virObjectLock(devs); + if (devices && + VIR_ALLOC_N(data.devices, virHashSize(devs->objs) + 1) < 0) { + virObjectUnlock(devs); + return -1; + } - if (devices && VIR_ALLOC_N(tmp_devices, devs->count + 1) < 0) - goto cleanup; + virHashForEach(devs->objs, virNodeDeviceObjListExportCallback, &data); + virObjectUnlock(devs); - for (i = 0; i < devs->count; i++) { - virNodeDeviceObjPtr obj = devs->objs[i]; - virObjectLock(obj); - if ((!aclfilter || aclfilter(conn, obj->def)) && - virNodeDeviceMatch(obj, flags)) { - if (devices) { - if (!(device = virGetNodeDevice(conn, obj->def->name)) || - VIR_STRDUP(device->parent, obj->def->parent) < 0) { - virObjectUnref(device); - virObjectUnlock(obj); - goto cleanup; - } - tmp_devices[ndevices] = device; - } - ndevices++; - } - virObjectUnlock(obj); - } + if (data.error) + goto cleanup; - if (tmp_devices) { - /* trim the array to the final size */ - ignore_value(VIR_REALLOC_N(tmp_devices, ndevices + 1)); - *devices = tmp_devices; - tmp_devices = NULL; - } + if (data.devices) { + ignore_value(VIR_REALLOC_N(data.devices, data.ndevices + 1)); + *devices = data.devices; + } - ret = ndevices; + return data.ndevices; cleanup: - if (tmp_devices) { - for (i = 0; i < ndevices; i++) - virObjectUnref(tmp_devices[i]); - } - - VIR_FREE(tmp_devices); - return ret; + virObjectListFree(data.devices); + return -1; } -- 2.9.4

On Thu, Jul 20, 2017 at 10:08:14AM -0400, John Ferlan wrote:
Rather than use a forward linked list of elements, it'll be much more efficient to use a hash table to reference the elements by unique name and to perform hash searches.
This patch does all the heavy lifting of converting the list object to use a self locking list that contains the hash table. Each of the FindBy functions that do not involve finding the object by it's key (name) is converted to use virHashSearch in order to find the specific object. When searching for the key (name), it's possible to use virHashLookup. For any of the list perusal functions that are required to evaluate each object, the virHashForEach function is used.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/conf/virnodedeviceobj.c | 575 ++++++++++++++++++++++++++++++-------------- 1 file changed, 400 insertions(+), 175 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 035a56d..58481e7 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -25,6 +25,7 @@ #include "viralloc.h" #include "virnodedeviceobj.h" #include "virerror.h" +#include "virhash.h" #include "virlog.h" #include "virstring.h"
@@ -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 */ + 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;
As we discussed in v5, I'd like you to drop ^these @def (and only @def...) declarations and usages across the whole patch for the reasons I already mentioned - it makes sense in general, but it's not very useful in this specific case.
+ const char *sysfs_path = opaque; + int want = 0; + + virObjectLock(obj); + def = obj->def;
...
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, NULL); + virObjectRef(obj); + virObjectUnlock(devs);
+ 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;
With reference to v5: The fact that creating a helper wasn't met with an agreement from the reviewer's side in one case doesn't mean it doesn't make sense to do in an other case, like this one. So, what I actually meant by creating a helper for: BySysfsPath ByWWNs ByFabricWWN ByCap ByCapSCSIByWWNs is just simply move the lock and search logic to a separate function, that's all, see my attached patch. And then, as you suggested in your v5 response to this patch, we can move from here (my patch included) and potentially do some more refactoring. ACK if you move the lock-search-ref-unlock-return snippets to a separate function for the cases mentioned above. Erik

On 07/24/2017 03:52 AM, Erik Skultety wrote:
On Thu, Jul 20, 2017 at 10:08:14AM -0400, John Ferlan wrote:
Rather than use a forward linked list of elements, it'll be much more efficient to use a hash table to reference the elements by unique name and to perform hash searches.
This patch does all the heavy lifting of converting the list object to use a self locking list that contains the hash table. Each of the FindBy functions that do not involve finding the object by it's key (name) is converted to use virHashSearch in order to find the specific object. When searching for the key (name), it's possible to use virHashLookup. For any of the list perusal functions that are required to evaluate each object, the virHashForEach function is used.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/conf/virnodedeviceobj.c | 575 ++++++++++++++++++++++++++++++-------------- 1 file changed, 400 insertions(+), 175 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 035a56d..58481e7 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -25,6 +25,7 @@ #include "viralloc.h" #include "virnodedeviceobj.h" #include "virerror.h" +#include "virhash.h" #include "virlog.h" #include "virstring.h"
@@ -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 */ + 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;
As we discussed in v5, I'd like you to drop ^these @def (and only @def...) declarations and usages across the whole patch for the reasons I already mentioned - it makes sense in general, but it's not very useful in this specific case.
<sigh> OK, I really do dislike the obj->def->X syntax "just" for a few functions while others use the @def nomenclature.
+ const char *sysfs_path = opaque; + int want = 0; + + virObjectLock(obj); + def = obj->def;
...
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, NULL); + virObjectRef(obj); + virObjectUnlock(devs);
+ 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;
With reference to v5: The fact that creating a helper wasn't met with an agreement from the reviewer's side in one case doesn't mean it doesn't make sense to do in an other case, like this one. So, what I actually meant by creating a helper for:
BySysfsPath ByWWNs ByFabricWWN ByCap ByCapSCSIByWWNs
is just simply move the lock and search logic to a separate function, that's all, see my attached patch. And then, as you suggested in your v5 response to this patch, we can move from here (my patch included) and potentially do some more refactoring.
Replies don't include your patch; however, I will note if you jump to patch 13: https://www.redhat.com/archives/libvir-list/2017-June/msg00929.html of the virObject series I posted last month: https://www.redhat.com/archives/libvir-list/2017-June/msg00916.html that you'll see that is the direction this would be headed anyway. I can do this sooner that's fine, although I prefer the name virNodeDeviceObjListSearch as opposed to virNodeDeviceObjListFindHelper. Ironically though you didn't like the @def usage, still you chose virHashSearcher cb = $functionName which has one use to be used as an argument to the function even though $functionName could be used directly in the call. The only advantage of @cb is that it reduces the line length of the call. John
ACK if you move the lock-search-ref-unlock-return snippets to a separate function for the cases mentioned above.
Erik

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, NULL); + virObjectRef(obj); + virObjectUnlock(devs);
+ 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;
With reference to v5: The fact that creating a helper wasn't met with an agreement from the reviewer's side in one case doesn't mean it doesn't make sense to do in an other case, like this one. So, what I actually meant by creating a helper for:
BySysfsPath ByWWNs ByFabricWWN ByCap ByCapSCSIByWWNs
is just simply move the lock and search logic to a separate function, that's all, see my attached patch. And then, as you suggested in your v5 response to this patch, we can move from here (my patch included) and potentially do some more refactoring.
Replies don't include your patch; however, I will note if you jump to patch 13:
What do you mean? Don't you see squash.patch in the attachment? (yes, I attached a patch instead of inlining it, the reason for that being that the patch is not particularly small and inlining it would disrupt the thread...)
https://www.redhat.com/archives/libvir-list/2017-June/msg00929.html
of the virObject series I posted last month:
https://www.redhat.com/archives/libvir-list/2017-June/msg00916.html
that you'll see that is the direction this would be headed anyway. I can do this sooner that's fine, although I prefer the name virNodeDeviceObjListSearch as opposed to virNodeDeviceObjListFindHelper.
Yeah, ok, since I'd rather not review multiple series that more-or-less depend on each other in parallel and try to connect relating changes back and forth, I couldn't have noticed this fact, but looking at the patch you linked, sure, the approach is the same. As long as the change we're discussing makes it in (one way or the other), I'm fine with it.
Ironically though you didn't like the @def usage, still you chose virHashSearcher cb = $functionName which has one use to be used as an
Alright, fair point, any further discussion would be unnecessary, act like I didn't say anything. My ACK still stands. Erik

On 07/24/2017 09:08 AM, Erik Skultety wrote:
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, NULL); + virObjectRef(obj); + virObjectUnlock(devs);
+ 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;
With reference to v5: The fact that creating a helper wasn't met with an agreement from the reviewer's side in one case doesn't mean it doesn't make sense to do in an other case, like this one. So, what I actually meant by creating a helper for:
BySysfsPath ByWWNs ByFabricWWN ByCap ByCapSCSIByWWNs
is just simply move the lock and search logic to a separate function, that's all, see my attached patch. And then, as you suggested in your v5 response to this patch, we can move from here (my patch included) and potentially do some more refactoring.
Replies don't include your patch; however, I will note if you jump to patch 13:
What do you mean? Don't you see squash.patch in the attachment? (yes, I attached a patch instead of inlining it, the reason for that being that the patch is not particularly small and inlining it would disrupt the thread...)
Oh - I meant when I reply to your patch with an attachment, I don't get your attachment in the reply. So I guess it was a early morning and feeble attempt to note that one had to go look at your reply in order to get context! I've altered the two @def in the callback functions to be "obj->def->sysfs_path" and "obj->def->caps". I've also made the single virHashSearch API/helper.... I also changed the comment in my branch for this patch (from v5 review) to say "lookup-by-name" instead of "lookup-by-uuid" and modified the comment in .4 to be appropriately placed. Just running things through a couple of tests before doing the push... Thanks - John
https://www.redhat.com/archives/libvir-list/2017-June/msg00929.html
of the virObject series I posted last month:
https://www.redhat.com/archives/libvir-list/2017-June/msg00916.html
that you'll see that is the direction this would be headed anyway. I can do this sooner that's fine, although I prefer the name virNodeDeviceObjListSearch as opposed to virNodeDeviceObjListFindHelper.
Yeah, ok, since I'd rather not review multiple series that more-or-less depend on each other in parallel and try to connect relating changes back and forth, I couldn't have noticed this fact, but looking at the patch you linked, sure, the approach is the same. As long as the change we're discussing makes it in (one way or the other), I'm fine with it.
Ironically though you didn't like the @def usage, still you chose virHashSearcher cb = $functionName which has one use to be used as an
Alright, fair point, any further discussion would be unnecessary, act like I didn't say anything.> My ACK still stands.
Erik

Replies don't include your patch; however, I will note if you jump to patch 13:
What do you mean? Don't you see squash.patch in the attachment? (yes, I attached a patch instead of inlining it, the reason for that being that the patch is not particularly small and inlining it would disrupt the thread...)
Oh - I meant when I reply to your patch with an attachment, I don't get your attachment in the reply. So I guess it was a early morning and feeble attempt to note that one had to go look at your reply in order to get context!
Nah, it's just my poor English - I could have considered other meanings, I just went with the most straightforward without thinking about it much, it does make sense now that you helped to steer the light so it could dawn on the marblehead. Erik

Since virnodedeviceobj now has a self-lockable hash table, there's no need to lock the table from the driver for processing. Thus remove the locks from the driver for NodeDeviceObjList mgmt. This includes the test driver as well. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/node_device/node_device_driver.c | 61 +++++++----------------------------- src/node_device/node_device_hal.c | 16 ++-------- src/node_device/node_device_udev.c | 13 +++----- src/test/test_driver.c | 25 +++------------ 4 files changed, 22 insertions(+), 93 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 920d877..facfeb6 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -174,19 +174,13 @@ nodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags) { - int ndevs = 0; - if (virNodeNumOfDevicesEnsureACL(conn) < 0) return -1; virCheckFlags(0, -1); - nodeDeviceLock(); - ndevs = virNodeDeviceObjListNumOfDevices(driver->devs, conn, cap, - virNodeNumOfDevicesCheckACL); - nodeDeviceUnlock(); - - return ndevs; + return virNodeDeviceObjListNumOfDevices(driver->devs, conn, cap, + virNodeNumOfDevicesCheckACL); } @@ -197,20 +191,14 @@ nodeListDevices(virConnectPtr conn, int maxnames, unsigned int flags) { - int nnames; - if (virNodeListDevicesEnsureACL(conn) < 0) return -1; virCheckFlags(0, -1); - nodeDeviceLock(); - nnames = virNodeDeviceObjListGetNames(driver->devs, conn, - virNodeListDevicesCheckACL, - cap, names, maxnames); - nodeDeviceUnlock(); - - return nnames; + return virNodeDeviceObjListGetNames(driver->devs, conn, + virNodeListDevicesCheckACL, + cap, names, maxnames); } @@ -219,19 +207,14 @@ nodeConnectListAllNodeDevices(virConnectPtr conn, virNodeDevicePtr **devices, unsigned int flags) { - int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP, -1); if (virConnectListAllNodeDevicesEnsureACL(conn) < 0) return -1; - nodeDeviceLock(); - ret = virNodeDeviceObjListExport(conn, driver->devs, devices, - virConnectListAllNodeDevicesCheckACL, - flags); - nodeDeviceUnlock(); - return ret; + return virNodeDeviceObjListExport(conn, driver->devs, devices, + virConnectListAllNodeDevicesCheckACL, + flags); } @@ -240,11 +223,7 @@ nodeDeviceObjFindByName(const char *name) { virNodeDeviceObjPtr obj; - nodeDeviceLock(); - obj = virNodeDeviceObjListFindByName(driver->devs, name); - nodeDeviceUnlock(); - - if (!obj) { + if (!(obj = virNodeDeviceObjListFindByName(driver->devs, name))) { virReportError(VIR_ERR_NO_NODE_DEVICE, _("no node device with matching name '%s'"), name); @@ -294,11 +273,8 @@ nodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, virCheckFlags(0, NULL); - nodeDeviceLock(); - obj = virNodeDeviceObjListFindSCSIHostByWWNs(driver->devs, wwnn, wwpn); - nodeDeviceUnlock(); - - if (!obj) + if (!(obj = virNodeDeviceObjListFindSCSIHostByWWNs(driver->devs, + wwnn, wwpn))) return NULL; def = virNodeDeviceObjGetDef(obj); @@ -509,13 +485,6 @@ nodeDeviceFindNewDevice(virConnectPtr conn, virNodeDevicePtr device = NULL; time_t start = 0, now = 0; - /* The thread that creates the device takes the driver lock, so we - * must release it in order to allow the device to be created. - * We're not doing anything with the driver pointer at this point, - * so it's safe to release it, assuming that the pointer itself - * doesn't become invalid. */ - nodeDeviceUnlock(); - nodeDeviceGetTime(&start); while ((now - start) < LINUX_NEW_DEVICE_WAIT_TIME) { @@ -532,8 +501,6 @@ nodeDeviceFindNewDevice(virConnectPtr conn, break; } - nodeDeviceLock(); - return device; } @@ -552,8 +519,6 @@ nodeDeviceCreateXML(virConnectPtr conn, virCheckFlags(0, NULL); virt_type = virConnectGetType(conn); - nodeDeviceLock(); - if (!(def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, virt_type))) goto cleanup; @@ -579,7 +544,6 @@ nodeDeviceCreateXML(virConnectPtr conn, "wwnn '%s' and wwpn '%s'"), def->name, wwnn, wwpn); cleanup: - nodeDeviceUnlock(); virNodeDeviceDefFree(def); VIR_FREE(wwnn); VIR_FREE(wwpn); @@ -601,8 +565,6 @@ nodeDeviceDestroy(virNodeDevicePtr device) return -1; def = virNodeDeviceObjGetDef(obj); - nodeDeviceLock(); - if (virNodeDeviceDestroyEnsureACL(device->conn, def) < 0) goto cleanup; @@ -634,7 +596,6 @@ nodeDeviceDestroy(virNodeDevicePtr device) ret = 0; cleanup: - nodeDeviceUnlock(); virNodeDeviceObjEndAPI(&obj); VIR_FREE(parent); VIR_FREE(wwnn); diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 7f246f0..c19e327 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -508,20 +508,15 @@ dev_refresh(const char *udi) const char *name = hal_name(udi); virNodeDeviceObjPtr obj; - nodeDeviceLock(); if ((obj = virNodeDeviceObjListFindByName(driver->devs, name))) { /* Simply "rediscover" device -- incrementally handling changes * to sub-capabilities (like net.80203) is nasty ... so avoid it. */ virNodeDeviceObjListRemove(driver->devs, obj); - } else { - VIR_DEBUG("no device named %s", name); - } - nodeDeviceUnlock(); - - if (obj) { virObjectUnref(obj); dev_create(udi); + } else { + VIR_DEBUG("no device named %s", name); } } @@ -541,14 +536,12 @@ device_removed(LibHalContext *ctx ATTRIBUTE_UNUSED, const char *name = hal_name(udi); virNodeDeviceObjPtr obj; - nodeDeviceLock(); obj = virNodeDeviceObjListFindByName(driver->devs, name); VIR_DEBUG("%s", name); if (obj) virNodeDeviceObjListRemove(driver->devs, obj); else VIR_DEBUG("no device named %s", name); - nodeDeviceUnlock(); virObjectUnref(obj); } @@ -561,11 +554,8 @@ device_cap_added(LibHalContext *ctx, virNodeDeviceObjPtr obj; virNodeDeviceDefPtr def; - nodeDeviceLock(); - obj = virNodeDeviceObjListFindByName(driver->devs, name); - nodeDeviceUnlock(); VIR_DEBUG("%s %s", cap, name); - if (obj) { + if ((obj = virNodeDeviceObjListFindByName(driver->devs, name))) { def = virNodeDeviceObjGetDef(obj); (void)gather_capability(ctx, udi, cap, &def->caps); virNodeDeviceObjEndAPI(&obj); diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 1b10c16..434efd7 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1607,7 +1607,6 @@ udevEventHandleCallback(int watch ATTRIBUTE_UNUSED, const char *action = NULL; int udev_fd = -1; - nodeDeviceLock(); udev_fd = udev_monitor_get_fd(udev_monitor); if (fd != udev_fd) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -1639,7 +1638,6 @@ udevEventHandleCallback(int watch ATTRIBUTE_UNUSED, cleanup: udev_device_unref(device); - nodeDeviceUnlock(); return; } @@ -1767,7 +1765,6 @@ nodeStateInitialize(bool privileged, { udevPrivate *priv = NULL; struct udev *udev = NULL; - int ret = -1; if (VIR_ALLOC(priv) < 0) return -1; @@ -1847,18 +1844,16 @@ nodeStateInitialize(bool privileged, goto cleanup; /* Populate with known devices */ - + nodeDeviceUnlock(); if (udevEnumerateDevices(udev) != 0) goto cleanup; - ret = 0; + return 0; cleanup: nodeDeviceUnlock(); - - if (ret == -1) - nodeStateCleanup(); - return ret; + nodeStateCleanup(); + return -1; } diff --git a/src/test/test_driver.c b/src/test/test_driver.c index bb2e7ba..4702690 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5303,11 +5303,7 @@ testNodeDeviceObjFindByName(testDriverPtr driver, { virNodeDeviceObjPtr obj; - testDriverLock(driver); - obj = virNodeDeviceObjListFindByName(driver->devs, name); - testDriverUnlock(driver); - - if (!obj) + if (!(obj = virNodeDeviceObjListFindByName(driver->devs, name))) virReportError(VIR_ERR_NO_NODE_DEVICE, _("no node device with matching name '%s'"), name); @@ -5322,15 +5318,10 @@ testNodeNumOfDevices(virConnectPtr conn, unsigned int flags) { testDriverPtr driver = conn->privateData; - int ndevs = 0; virCheckFlags(0, -1); - testDriverLock(driver); - ndevs = virNodeDeviceObjListNumOfDevices(driver->devs, conn, cap, NULL); - testDriverUnlock(driver); - - return ndevs; + return virNodeDeviceObjListNumOfDevices(driver->devs, conn, cap, NULL); } @@ -5342,16 +5333,11 @@ testNodeListDevices(virConnectPtr conn, unsigned int flags) { testDriverPtr driver = conn->privateData; - int nnames = 0; virCheckFlags(0, -1); - testDriverLock(driver); - nnames = virNodeDeviceObjListGetNames(driver->devs, conn, NULL, - cap, names, maxnames); - testDriverUnlock(driver); - - return nnames; + return virNodeDeviceObjListGetNames(driver->devs, conn, NULL, + cap, names, maxnames); } @@ -5566,8 +5552,6 @@ testNodeDeviceCreateXML(virConnectPtr conn, virCheckFlags(0, NULL); - testDriverLock(driver); - if (!(def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL))) goto cleanup; @@ -5604,7 +5588,6 @@ testNodeDeviceCreateXML(virConnectPtr conn, cleanup: virNodeDeviceObjEndAPI(&obj); - testDriverUnlock(driver); virNodeDeviceDefFree(def); virObjectUnref(dev); VIR_FREE(wwnn); -- 2.9.4

On Thu, Jul 20, 2017 at 10:08:15AM -0400, John Ferlan wrote:
Since virnodedeviceobj now has a self-lockable hash table, there's no need to lock the table from the driver for processing. Thus remove the locks from the driver for NodeDeviceObjList mgmt.
This includes the test driver as well.
Signed-off-by: John Ferlan <jferlan@redhat.com>
...
/* Populate with known devices */
^This comment should come after the unlock, so it's 100% clear it's linked to the udevEnumerateDevices call.
- + nodeDeviceUnlock(); if (udevEnumerateDevices(udev) != 0) goto cleanup;
- ret = 0; + return 0;
cleanup: nodeDeviceUnlock(); - - if (ret == -1) - nodeStateCleanup(); - return ret; + nodeStateCleanup(); + return -1; }
The patch is straightforward, if there is a spot where you forgot to handle the locks in a similar manner and I missed it, either I will hit it with my follow-up "mdev nodedev-list kernel race" series or someone else eventually will :). ACK to 1,2 and this one, I had some comments to 3, but ACK'd it in principle. Erik
participants (2)
-
Erik Skultety
-
John Ferlan