[libvirt] [PATCH v2 0/8] storage: Resolve some locking issues

Technically, this is a v2 of: https://www.redhat.com/archives/libvir-list/2018-August/msg00624.html but majority of the patches are new. The review of the patch from above made me look into storage pool locking more and I have found some issues. For best view of the patches (esp. 4/8 use --histogram option). Michal Prívozník (8): storage_backend_rbd: Drop ATTRIBUTE_UNUSED for arguments that are used virstorageobj: Move virStoragePoolObjIsDuplicate up virstorageobj: Check for duplicates from virStoragePoolObjAssignDef virstorageobj: Move virStoragePoolObjSourceFindDuplicate and friends up virStoragePoolObjSourceFindDuplicate: Drop @conn argument virstorageobj: Check for source duplicates from virStoragePoolObjAssignDef storage_driver: Mark volume as 'in use' for some operations storage_driver: Release pool object lock for some long running jobs src/conf/virstorageobj.c | 937 +++++++++++++++-------------- src/conf/virstorageobj.h | 13 +- src/libvirt_private.syms | 2 - src/storage/storage_backend_iscsi_direct.c | 6 +- src/storage/storage_backend_rbd.c | 12 +- src/storage/storage_driver.c | 56 +- src/test/test_driver.c | 12 +- 7 files changed, 529 insertions(+), 509 deletions(-) -- 2.16.4

In two places the passed pool object argument is marked as ATTRIBUTE_UNUSED even though it's used right away. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index 642cacb673..c6fb791a81 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -1063,7 +1063,7 @@ virStorageBackendRBDBuildVolFrom(virStoragePoolObjPtr pool, } static int -virStorageBackendRBDRefreshVol(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, +virStorageBackendRBDRefreshVol(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) { virStorageBackendRBDStatePtr ptr = NULL; @@ -1083,7 +1083,7 @@ virStorageBackendRBDRefreshVol(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, } static int -virStorageBackendRBDResizeVol(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, +virStorageBackendRBDResizeVol(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned long long capacity, unsigned int flags) -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
In two places the passed pool object argument is marked as ATTRIBUTE_UNUSED even though it's used right away.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com> Although freeze hasn't been announced, an rc1 tag exists - so I'll state that although the first 2 patches could be designated safe for freeze, the rest of the series needs to wait until after 4.7.0. John

On 08/28/2018 03:30 PM, John Ferlan wrote:
On 08/20/2018 08:09 AM, Michal Privoznik wrote:
In two places the passed pool object argument is marked as ATTRIBUTE_UNUSED even though it's used right away.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com>
Although freeze hasn't been announced, an rc1 tag exists - so I'll state that although the first 2 patches could be designated safe for freeze, the rest of the series needs to wait until after 4.7.0.
Well, the whole patch set can be viewed as a bug fix and as such is exempt from freeze ;-) Michal

On 08/28/2018 09:58 AM, Michal Privoznik wrote:
On 08/28/2018 03:30 PM, John Ferlan wrote:
On 08/20/2018 08:09 AM, Michal Privoznik wrote:
In two places the passed pool object argument is marked as ATTRIBUTE_UNUSED even though it's used right away.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com>
Although freeze hasn't been announced, an rc1 tag exists - so I'll state that although the first 2 patches could be designated safe for freeze, the rest of the series needs to wait until after 4.7.0.
Well, the whole patch set can be viewed as a bug fix and as such is exempt from freeze ;-)
Careful there you don't want to set a dangerous precedent, that I could use ;-)... Still, I see no bz associated with any patch in the series. Also there are three distinct things happening in this series. 1. Moving the Is/Find duplicate code into AssignDef for TOCTOU. That's a lot of moving parts and some amount of logic adjustment that should get more exposure than a few RC days. 2. The usage of in_use during download, upload, and wipe 3. Release of pool lock while in_use is set for more concurrency I think 2 is a "easy" bug, 1 is a "hard" bug, and 3 is less a bug and more a concurrency enhancement. When it comes to late in the game, trivial things (like patch 1), easy bugs, patches associated w/ customer bzs, and crash/core type bugs could/should be fixed. But harder to reproduce and/or present in more than the current (months) release can/should wait. Of course JMO... John

This function is going to be made static in used in virStoragePoolObjAssignDef(). Therefore move it a few lines up. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 124 +++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index 6f1e14ed3e..185822451b 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1047,6 +1047,68 @@ virStoragePoolObjVolumeListExport(virConnectPtr conn, } +/* + * virStoragePoolObjIsDuplicate: + * @doms : virStoragePoolObjListPtr to search + * @def : virStoragePoolDefPtr definition of pool to lookup + * @check_active: If true, ensure that pool is not active + * + * Returns: -1 on error + * 0 if pool is new + * 1 if pool is a duplicate + */ +int +virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, + virStoragePoolDefPtr def, + bool check_active) +{ + int ret = -1; + virStoragePoolObjPtr obj = NULL; + + /* See if a Pool with matching UUID already exists */ + obj = virStoragePoolObjFindByUUID(pools, def->uuid); + if (obj) { + /* UUID matches, but if names don't match, refuse it */ + if (STRNEQ(obj->def->name, def->name)) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->def->uuid, uuidstr); + virReportError(VIR_ERR_OPERATION_FAILED, + _("pool '%s' is already defined with uuid %s"), + obj->def->name, uuidstr); + goto cleanup; + } + + if (check_active) { + /* UUID & name match, but if Pool is already active, refuse it */ + if (virStoragePoolObjIsActive(obj)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("pool is already active as '%s'"), + obj->def->name); + goto cleanup; + } + } + + ret = 1; + } else { + /* UUID does not match, but if a name matches, refuse it */ + obj = virStoragePoolObjFindByName(pools, def->name); + if (obj) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->def->uuid, uuidstr); + virReportError(VIR_ERR_OPERATION_FAILED, + _("pool '%s' already exists with uuid %s"), + def->name, uuidstr); + goto cleanup; + } + ret = 0; + } + + cleanup: + virStoragePoolObjEndAPI(&obj); + return ret; +} + + /** * virStoragePoolObjAssignDef: * @pools: Storage Pool object list pointer @@ -1452,68 +1514,6 @@ virStoragePoolObjGetNames(virStoragePoolObjListPtr pools, } -/* - * virStoragePoolObjIsDuplicate: - * @doms : virStoragePoolObjListPtr to search - * @def : virStoragePoolDefPtr definition of pool to lookup - * @check_active: If true, ensure that pool is not active - * - * Returns: -1 on error - * 0 if pool is new - * 1 if pool is a duplicate - */ -int -virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def, - bool check_active) -{ - int ret = -1; - virStoragePoolObjPtr obj = NULL; - - /* See if a Pool with matching UUID already exists */ - obj = virStoragePoolObjFindByUUID(pools, def->uuid); - if (obj) { - /* UUID matches, but if names don't match, refuse it */ - if (STRNEQ(obj->def->name, def->name)) { - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(obj->def->uuid, uuidstr); - virReportError(VIR_ERR_OPERATION_FAILED, - _("pool '%s' is already defined with uuid %s"), - obj->def->name, uuidstr); - goto cleanup; - } - - if (check_active) { - /* UUID & name match, but if Pool is already active, refuse it */ - if (virStoragePoolObjIsActive(obj)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("pool is already active as '%s'"), - obj->def->name); - goto cleanup; - } - } - - ret = 1; - } else { - /* UUID does not match, but if a name matches, refuse it */ - obj = virStoragePoolObjFindByName(pools, def->name); - if (obj) { - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(obj->def->uuid, uuidstr); - virReportError(VIR_ERR_OPERATION_FAILED, - _("pool '%s' already exists with uuid %s"), - def->name, uuidstr); - goto cleanup; - } - ret = 0; - } - - cleanup: - virStoragePoolObjEndAPI(&obj); - return ret; -} - - static int getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host, unsigned int *hostnum) -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
This function is going to be made static in used in virStoragePoolObjAssignDef(). Therefore move it a few lines up.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 124 +++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 62 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com> John

Even though we do some checking is not as thorough as it should be. We already have virStoragePoolObjIsDuplicate but the way we use it is a typical TOCTOU. Imagine two threads trying to define two pools with the same name but different UUIDs. With the current code neither of them finds a duplicate and thus proceed to virStoragePoolObjAssignDef where only names are compared. Therefore both threads succeed which is obviously wrong. We should check for duplicates where we care for them. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 39 +++++++++++++++++++++++++++------------ src/conf/virstorageobj.h | 8 ++------ src/libvirt_private.syms | 1 - src/storage/storage_driver.c | 10 ++-------- src/test/test_driver.c | 12 +++--------- 5 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index 185822451b..ea0ae6fd86 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1052,22 +1052,28 @@ virStoragePoolObjVolumeListExport(virConnectPtr conn, * @doms : virStoragePoolObjListPtr to search * @def : virStoragePoolDefPtr definition of pool to lookup * @check_active: If true, ensure that pool is not active + * @objRet: returned pool object * - * Returns: -1 on error + * Assumes @pools is locked by caller already. + * + * Returns: -1 on error (name or UUID mismatch) * 0 if pool is new - * 1 if pool is a duplicate + * 1 if pool is a duplicate (name and UUID match) */ -int +static int virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, virStoragePoolDefPtr def, - bool check_active) + bool check_active, + virStoragePoolObjPtr *objRet) { int ret = -1; virStoragePoolObjPtr obj = NULL; /* See if a Pool with matching UUID already exists */ - obj = virStoragePoolObjFindByUUID(pools, def->uuid); + obj = virStoragePoolObjFindByUUIDLocked(pools, def->uuid); if (obj) { + virObjectLock(obj); + /* UUID matches, but if names don't match, refuse it */ if (STRNEQ(obj->def->name, def->name)) { char uuidstr[VIR_UUID_STRING_BUFLEN]; @@ -1088,11 +1094,14 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, } } + VIR_STEAL_PTR(*objRet, obj); ret = 1; } else { /* UUID does not match, but if a name matches, refuse it */ - obj = virStoragePoolObjFindByName(pools, def->name); + obj = virStoragePoolObjFindByNameLocked(pools, def->name); if (obj) { + virObjectLock(obj); + char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(obj->def->uuid, uuidstr); virReportError(VIR_ERR_OPERATION_FAILED, @@ -1113,6 +1122,7 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, * virStoragePoolObjAssignDef: * @pools: Storage Pool object list pointer * @def: Storage pool definition to add or update + * @check_active: If true, ensure that pool is not active * * Lookup the @def to see if it already exists in the @pools in order * to either update or add if it does not exist. @@ -1121,15 +1131,20 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, */ virStoragePoolObjPtr virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def) + virStoragePoolDefPtr def, + bool check_active) { - virStoragePoolObjPtr obj; + virStoragePoolObjPtr obj = NULL; char uuidstr[VIR_UUID_STRING_BUFLEN]; + int rc; virObjectRWLockWrite(pools); - if ((obj = virStoragePoolObjFindByNameLocked(pools, def->name))) { - virObjectLock(obj); + rc = virStoragePoolObjIsDuplicate(pools, def, check_active, &obj); + + if (rc < 0) + goto error; + if (rc > 0) { if (!virStoragePoolObjIsActive(obj)) { virStoragePoolDefFree(obj->def); obj->def = def; @@ -1186,7 +1201,7 @@ virStoragePoolObjLoad(virStoragePoolObjListPtr pools, return NULL; } - if (!(obj = virStoragePoolObjAssignDef(pools, def))) { + if (!(obj = virStoragePoolObjAssignDef(pools, def, false))) { virStoragePoolDefFree(def); return NULL; } @@ -1248,7 +1263,7 @@ virStoragePoolObjLoadState(virStoragePoolObjListPtr pools, } /* create the object */ - if (!(obj = virStoragePoolObjAssignDef(pools, def))) + if (!(obj = virStoragePoolObjAssignDef(pools, def, true))) goto error; /* XXX: future handling of some additional useful status data, diff --git a/src/conf/virstorageobj.h b/src/conf/virstorageobj.h index dd7001c4b2..9fabf34e4f 100644 --- a/src/conf/virstorageobj.h +++ b/src/conf/virstorageobj.h @@ -189,7 +189,8 @@ virStoragePoolObjVolumeListExport(virConnectPtr conn, virStoragePoolObjPtr virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def); + virStoragePoolDefPtr def, + bool check_active); int virStoragePoolObjSaveDef(virStorageDriverStatePtr driver, @@ -244,11 +245,6 @@ void virStoragePoolObjRemove(virStoragePoolObjListPtr pools, virStoragePoolObjPtr obj); -int -virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def, - bool check_active); - int virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, virStoragePoolObjListPtr pools, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ca4a192a4a..572d1a1e22 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1140,7 +1140,6 @@ virStoragePoolObjGetVolumesCount; virStoragePoolObjIncrAsyncjobs; virStoragePoolObjIsActive; virStoragePoolObjIsAutostart; -virStoragePoolObjIsDuplicate; virStoragePoolObjListExport; virStoragePoolObjListForEach; virStoragePoolObjListNew; diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index c108f026ce..18a67ec8ac 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -705,16 +705,13 @@ storagePoolCreateXML(virConnectPtr conn, if (virStoragePoolCreateXMLEnsureACL(conn, newDef) < 0) goto cleanup; - if (virStoragePoolObjIsDuplicate(driver->pools, newDef, true) < 0) - goto cleanup; - if (virStoragePoolObjSourceFindDuplicate(conn, driver->pools, newDef) < 0) goto cleanup; if ((backend = virStorageBackendForType(newDef->type)) == NULL) goto cleanup; - if (!(obj = virStoragePoolObjAssignDef(driver->pools, newDef))) + if (!(obj = virStoragePoolObjAssignDef(driver->pools, newDef, true))) goto cleanup; newDef = NULL; def = virStoragePoolObjGetDef(obj); @@ -799,16 +796,13 @@ storagePoolDefineXML(virConnectPtr conn, if (virStoragePoolDefineXMLEnsureACL(conn, newDef) < 0) goto cleanup; - if (virStoragePoolObjIsDuplicate(driver->pools, newDef, false) < 0) - goto cleanup; - if (virStoragePoolObjSourceFindDuplicate(conn, driver->pools, newDef) < 0) goto cleanup; if (virStorageBackendForType(newDef->type) == NULL) goto cleanup; - if (!(obj = virStoragePoolObjAssignDef(driver->pools, newDef))) + if (!(obj = virStoragePoolObjAssignDef(driver->pools, newDef, false))) goto cleanup; newDef = virStoragePoolObjGetNewDef(obj); def = virStoragePoolObjGetDef(obj); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 6697a7dfe6..c1f31b461c 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1108,7 +1108,7 @@ testParseStorage(testDriverPtr privconn, if (!def) goto error; - if (!(obj = virStoragePoolObjAssignDef(privconn->pools, def))) { + if (!(obj = virStoragePoolObjAssignDef(privconn->pools, def, false))) { virStoragePoolDefFree(def); goto error; } @@ -4515,10 +4515,7 @@ testStoragePoolCreateXML(virConnectPtr conn, if (!(newDef = virStoragePoolDefParseString(xml))) goto cleanup; - if (virStoragePoolObjIsDuplicate(privconn->pools, newDef, true) < 0) - goto cleanup; - - if (!(obj = virStoragePoolObjAssignDef(privconn->pools, newDef))) + if (!(obj = virStoragePoolObjAssignDef(privconn->pools, newDef, true))) goto cleanup; newDef = NULL; def = virStoragePoolObjGetDef(obj); @@ -4589,10 +4586,7 @@ testStoragePoolDefineXML(virConnectPtr conn, newDef->allocation = defaultPoolAlloc; newDef->available = defaultPoolCap - defaultPoolAlloc; - if (virStoragePoolObjIsDuplicate(privconn->pools, newDef, false) < 0) - goto cleanup; - - if (!(obj = virStoragePoolObjAssignDef(privconn->pools, newDef))) + if (!(obj = virStoragePoolObjAssignDef(privconn->pools, newDef, false))) goto cleanup; newDef = NULL; def = virStoragePoolObjGetDef(obj); -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
Even though we do some checking is not as thorough as it should
s/is not/it is not/
be. We already have virStoragePoolObjIsDuplicate but the way we use it is a typical TOCTOU. Imagine two threads trying to define two pools with the same name but different UUIDs. With the current code neither of them finds a duplicate and thus proceed to virStoragePoolObjAssignDef where only names are compared. Therefore both threads succeed which is obviously wrong.
We should check for duplicates where we care for them.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 39 +++++++++++++++++++++++++++------------ src/conf/virstorageobj.h | 8 ++------ src/libvirt_private.syms | 1 - src/storage/storage_driver.c | 10 ++-------- src/test/test_driver.c | 12 +++--------- 5 files changed, 34 insertions(+), 36 deletions(-)
After seeing patch 4, would it just be worthwhile to merge it into patch 2. There's 405 lines from the virStoragePoolObjAssignDef comments to that could move to just above virStoragePoolObjMatch. IDC either way, but since the patches that follow work off it it...
diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index 185822451b..ea0ae6fd86 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1052,22 +1052,28 @@ virStoragePoolObjVolumeListExport(virConnectPtr conn, * @doms : virStoragePoolObjListPtr to search * @def : virStoragePoolDefPtr definition of pool to lookup * @check_active: If true, ensure that pool is not active + * @objRet: returned pool object * - * Returns: -1 on error + * Assumes @pools is locked by caller already. + * + * Returns: -1 on error (name or UUID mismatch)
-1 on error (name/uuid mismatch *or* check_active failure) and /me wonders if we should move the check_active failure to the caller
* 0 if pool is new - * 1 if pool is a duplicate + * 1 if pool is a duplicate (name and UUID match)
"Implied" -1 and 0 return means obj == NULL, while 1 means obj is set.
*/ -int +static int virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
I think we should change the name to be virStoragePoolObjAssignFindPool or something similar since "IsDuplicate" probably should have returned true/false only given other libvirt method naming schemes. I'd be OK doing it all in one change too. Reviewed-by: John Ferlan <jferlan@redhat.com> John

This function is going to be made static in used in virStoragePoolObjAssignDef(). Therefore move it and all the static functions it calls a few lines up. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 788 +++++++++++++++++++++++------------------------ 1 file changed, 394 insertions(+), 394 deletions(-) diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index ea0ae6fd86..b710ec652d 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1118,6 +1118,400 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, } +static int +getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host, + unsigned int *hostnum) +{ + int ret = -1; + unsigned int num; + char *name = NULL; + + if (scsi_host->has_parent) { + virPCIDeviceAddressPtr addr = &scsi_host->parentaddr; + unsigned int unique_id = scsi_host->unique_id; + + if (!(name = virSCSIHostGetNameByParentaddr(addr->domain, + addr->bus, + addr->slot, + addr->function, + unique_id))) + goto cleanup; + if (virSCSIHostGetNumber(name, &num) < 0) + goto cleanup; + } else { + if (virSCSIHostGetNumber(scsi_host->name, &num) < 0) + goto cleanup; + } + + *hostnum = num; + ret = 0; + + cleanup: + VIR_FREE(name); + return ret; +} + + +static bool +virStorageIsSameHostnum(const char *name, + unsigned int scsi_hostnum) +{ + unsigned int fc_hostnum; + + if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 && + scsi_hostnum == fc_hostnum) + return true; + + return false; +} + + +/* + * matchFCHostToSCSIHost: + * + * @conn: Connection pointer + * @fchost: fc_host adapter ptr (either def or pool->def) + * @scsi_hostnum: Already determined "scsi_pool" hostnum + * + * Returns true/false whether there is a match between the incoming + * fc_adapter host# and the scsi_host host# + */ +static bool +matchFCHostToSCSIHost(virConnectPtr conn, + virStorageAdapterFCHostPtr fchost, + unsigned int scsi_hostnum) +{ + bool ret = false; + char *name = NULL; + char *scsi_host_name = NULL; + char *parent_name = NULL; + + /* If we have a parent defined, get its hostnum, and compare to the + * scsi_hostnum. If they are the same, then we have a match + */ + if (fchost->parent && + virStorageIsSameHostnum(fchost->parent, scsi_hostnum)) + return true; + + /* If we find an fc adapter name, then either libvirt created a vHBA + * for this fc_host or a 'virsh nodedev-create' generated a vHBA. + */ + if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) { + + /* Get the scsi_hostN for the vHBA in order to see if it + * matches our scsi_hostnum + */ + if (virStorageIsSameHostnum(name, scsi_hostnum)) { + ret = true; + goto cleanup; + } + + /* We weren't provided a parent, so we have to query the node + * device driver in order to ascertain the parent of the vHBA. + * If the parent fc_hostnum is the same as the scsi_hostnum, we + * have a match. + */ + if (conn && !fchost->parent) { + if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) + goto cleanup; + if ((parent_name = virNodeDeviceGetParentName(conn, + scsi_host_name))) { + if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) { + ret = true; + goto cleanup; + } + } else { + /* Throw away the error and fall through */ + virResetLastError(); + VIR_DEBUG("Could not determine parent vHBA"); + } + } + } + + /* NB: Lack of a name means that this vHBA hasn't yet been created, + * which means our scsi_host cannot be using the vHBA. Furthermore, + * lack of a provided parent means libvirt is going to choose the + * "best" fc_host capable adapter based on availabilty. That could + * conflict with an existing scsi_host definition, but there's no + * way to know that now. + */ + + cleanup: + VIR_FREE(name); + VIR_FREE(parent_name); + VIR_FREE(scsi_host_name); + return ret; +} + + +static bool +matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host, + virStorageAdapterSCSIHostPtr def_scsi_host) +{ + virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr; + virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr; + + if (pooladdr->domain == defaddr->domain && + pooladdr->bus == defaddr->bus && + pooladdr->slot == defaddr->slot && + pooladdr->function == defaddr->function && + pool_scsi_host->unique_id == def_scsi_host->unique_id) + return true; + + return false; +} + + +static bool +virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc, + virStoragePoolSourcePtr defsrc) +{ + if (poolsrc->nhost != 1 && defsrc->nhost != 1) + return false; + + if (defsrc->hosts[0].port && + poolsrc->hosts[0].port != defsrc->hosts[0].port) + return false; + + return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name); +} + + +static bool +virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) +{ + virStoragePoolSourcePtr poolsrc = &obj->def->source; + virStoragePoolSourcePtr defsrc = &def->source; + + /* NB: Do not check the source host name */ + if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn)) + return false; + + return true; +} + + +static virStoragePoolObjPtr +virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) +{ + if (obj->def->type == VIR_STORAGE_POOL_DIR) { + if (STREQ(obj->def->target.path, def->target.path)) + return obj; + } else if (obj->def->type == VIR_STORAGE_POOL_GLUSTER) { + if (STREQ(obj->def->source.name, def->source.name) && + STREQ_NULLABLE(obj->def->source.dir, def->source.dir) && + virStoragePoolSourceMatchSingleHost(&obj->def->source, + &def->source)) + return obj; + } else if (obj->def->type == VIR_STORAGE_POOL_NETFS) { + if (STREQ(obj->def->source.dir, def->source.dir) && + virStoragePoolSourceMatchSingleHost(&obj->def->source, + &def->source)) + return obj; + } + + return NULL; +} + + +static virStoragePoolObjPtr +virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def, + virConnectPtr conn) +{ + virStorageAdapterPtr pool_adapter = &obj->def->source.adapter; + virStorageAdapterPtr def_adapter = &def->source.adapter; + virStorageAdapterSCSIHostPtr pool_scsi_host; + virStorageAdapterSCSIHostPtr def_scsi_host; + virStorageAdapterFCHostPtr pool_fchost; + virStorageAdapterFCHostPtr def_fchost; + unsigned int pool_hostnum; + unsigned int def_hostnum; + unsigned int scsi_hostnum; + + if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { + pool_fchost = &pool_adapter->data.fchost; + def_fchost = &def_adapter->data.fchost; + + if (STREQ(pool_fchost->wwnn, def_fchost->wwnn) && + STREQ(pool_fchost->wwpn, def_fchost->wwpn)) + return obj; + } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { + pool_scsi_host = &pool_adapter->data.scsi_host; + def_scsi_host = &def_adapter->data.scsi_host; + + if (pool_scsi_host->has_parent && + def_scsi_host->has_parent && + matchSCSIAdapterParent(pool_scsi_host, def_scsi_host)) + return obj; + + if (getSCSIHostNumber(pool_scsi_host, &pool_hostnum) < 0 || + getSCSIHostNumber(def_scsi_host, &def_hostnum) < 0) + return NULL; + if (pool_hostnum == def_hostnum) + return obj; + } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { + pool_fchost = &pool_adapter->data.fchost; + def_scsi_host = &def_adapter->data.scsi_host; + + /* Get the scsi_hostN for the scsi_host source adapter def */ + if (getSCSIHostNumber(def_scsi_host, &scsi_hostnum) < 0) + return NULL; + + if (matchFCHostToSCSIHost(conn, pool_fchost, scsi_hostnum)) + return obj; + + } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { + pool_scsi_host = &pool_adapter->data.scsi_host; + def_fchost = &def_adapter->data.fchost; + + if (getSCSIHostNumber(pool_scsi_host, &scsi_hostnum) < 0) + return NULL; + + if (matchFCHostToSCSIHost(conn, def_fchost, scsi_hostnum)) + return obj; + } + + return NULL; +} + + +static virStoragePoolObjPtr +virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) +{ + virStoragePoolObjPtr matchobj = NULL; + + if (obj->def->type == VIR_STORAGE_POOL_ISCSI) { + if (def->type != VIR_STORAGE_POOL_ISCSI) + return NULL; + + if ((matchobj = virStoragePoolSourceFindDuplicateDevices(obj, def))) { + if (!virStoragePoolSourceISCSIMatch(matchobj, def)) + return NULL; + } + return matchobj; + } + + if (def->type == VIR_STORAGE_POOL_ISCSI) + return NULL; + + /* VIR_STORAGE_POOL_FS + * VIR_STORAGE_POOL_LOGICAL + * VIR_STORAGE_POOL_DISK + * VIR_STORAGE_POOL_ZFS */ + return virStoragePoolSourceFindDuplicateDevices(obj, def); +} + + +struct _virStoragePoolObjFindDuplicateData { + virConnectPtr conn; + virStoragePoolDefPtr def; +}; + +static int +virStoragePoolObjSourceFindDuplicateCb(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload; + struct _virStoragePoolObjFindDuplicateData *data = + (struct _virStoragePoolObjFindDuplicateData *) opaque; + + /* Don't match against ourself if re-defining existing pool ! */ + if (STREQ(obj->def->name, data->def->name)) + return 0; + + switch ((virStoragePoolType)obj->def->type) { + case VIR_STORAGE_POOL_DIR: + case VIR_STORAGE_POOL_GLUSTER: + case VIR_STORAGE_POOL_NETFS: + if (data->def->type == obj->def->type && + virStoragePoolObjSourceMatchTypeDIR(obj, data->def)) + return 1; + break; + + case VIR_STORAGE_POOL_SCSI: + if (data->def->type == obj->def->type && + virStoragePoolObjSourceMatchTypeISCSI(obj, data->def, data->conn)) + return 1; + break; + + case VIR_STORAGE_POOL_ISCSI: + case VIR_STORAGE_POOL_ISCSI_DIRECT: + case VIR_STORAGE_POOL_FS: + case VIR_STORAGE_POOL_LOGICAL: + case VIR_STORAGE_POOL_DISK: + case VIR_STORAGE_POOL_ZFS: + if ((data->def->type == VIR_STORAGE_POOL_ISCSI || + data->def->type == VIR_STORAGE_POOL_ISCSI_DIRECT || + data->def->type == VIR_STORAGE_POOL_FS || + data->def->type == VIR_STORAGE_POOL_LOGICAL || + data->def->type == VIR_STORAGE_POOL_DISK || + data->def->type == VIR_STORAGE_POOL_ZFS) && + virStoragePoolObjSourceMatchTypeDEVICE(obj, data->def)) + return 1; + break; + + case VIR_STORAGE_POOL_SHEEPDOG: + if (data->def->type == obj->def->type && + virStoragePoolSourceMatchSingleHost(&obj->def->source, + &data->def->source)) + return 1; + break; + + case VIR_STORAGE_POOL_MPATH: + /* Only one mpath pool is valid per host */ + if (data->def->type == obj->def->type) + return 1; + break; + + case VIR_STORAGE_POOL_VSTORAGE: + if (data->def->type == obj->def->type && + STREQ(obj->def->source.name, data->def->source.name)) + return 1; + break; + + case VIR_STORAGE_POOL_RBD: + case VIR_STORAGE_POOL_LAST: + break; + } + + return 0; +} + + +int +virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, + virStoragePoolObjListPtr pools, + virStoragePoolDefPtr def) +{ + struct _virStoragePoolObjFindDuplicateData data = { .conn = conn, + .def = def }; + virStoragePoolObjPtr obj = NULL; + + virObjectRWLockRead(pools); + obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb, + &data, NULL); + virObjectRWUnlock(pools); + + if (obj) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Storage source conflict with pool: '%s'"), + obj->def->name); + return -1; + } + + return 0; +} + + /** * virStoragePoolObjAssignDef: * @pools: Storage Pool object list pointer @@ -1529,400 +1923,6 @@ virStoragePoolObjGetNames(virStoragePoolObjListPtr pools, } -static int -getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host, - unsigned int *hostnum) -{ - int ret = -1; - unsigned int num; - char *name = NULL; - - if (scsi_host->has_parent) { - virPCIDeviceAddressPtr addr = &scsi_host->parentaddr; - unsigned int unique_id = scsi_host->unique_id; - - if (!(name = virSCSIHostGetNameByParentaddr(addr->domain, - addr->bus, - addr->slot, - addr->function, - unique_id))) - goto cleanup; - if (virSCSIHostGetNumber(name, &num) < 0) - goto cleanup; - } else { - if (virSCSIHostGetNumber(scsi_host->name, &num) < 0) - goto cleanup; - } - - *hostnum = num; - ret = 0; - - cleanup: - VIR_FREE(name); - return ret; -} - - -static bool -virStorageIsSameHostnum(const char *name, - unsigned int scsi_hostnum) -{ - unsigned int fc_hostnum; - - if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 && - scsi_hostnum == fc_hostnum) - return true; - - return false; -} - - -/* - * matchFCHostToSCSIHost: - * - * @conn: Connection pointer - * @fchost: fc_host adapter ptr (either def or pool->def) - * @scsi_hostnum: Already determined "scsi_pool" hostnum - * - * Returns true/false whether there is a match between the incoming - * fc_adapter host# and the scsi_host host# - */ -static bool -matchFCHostToSCSIHost(virConnectPtr conn, - virStorageAdapterFCHostPtr fchost, - unsigned int scsi_hostnum) -{ - bool ret = false; - char *name = NULL; - char *scsi_host_name = NULL; - char *parent_name = NULL; - - /* If we have a parent defined, get its hostnum, and compare to the - * scsi_hostnum. If they are the same, then we have a match - */ - if (fchost->parent && - virStorageIsSameHostnum(fchost->parent, scsi_hostnum)) - return true; - - /* If we find an fc adapter name, then either libvirt created a vHBA - * for this fc_host or a 'virsh nodedev-create' generated a vHBA. - */ - if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) { - - /* Get the scsi_hostN for the vHBA in order to see if it - * matches our scsi_hostnum - */ - if (virStorageIsSameHostnum(name, scsi_hostnum)) { - ret = true; - goto cleanup; - } - - /* We weren't provided a parent, so we have to query the node - * device driver in order to ascertain the parent of the vHBA. - * If the parent fc_hostnum is the same as the scsi_hostnum, we - * have a match. - */ - if (conn && !fchost->parent) { - if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) - goto cleanup; - if ((parent_name = virNodeDeviceGetParentName(conn, - scsi_host_name))) { - if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) { - ret = true; - goto cleanup; - } - } else { - /* Throw away the error and fall through */ - virResetLastError(); - VIR_DEBUG("Could not determine parent vHBA"); - } - } - } - - /* NB: Lack of a name means that this vHBA hasn't yet been created, - * which means our scsi_host cannot be using the vHBA. Furthermore, - * lack of a provided parent means libvirt is going to choose the - * "best" fc_host capable adapter based on availabilty. That could - * conflict with an existing scsi_host definition, but there's no - * way to know that now. - */ - - cleanup: - VIR_FREE(name); - VIR_FREE(parent_name); - VIR_FREE(scsi_host_name); - return ret; -} - - -static bool -matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host, - virStorageAdapterSCSIHostPtr def_scsi_host) -{ - virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr; - virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr; - - if (pooladdr->domain == defaddr->domain && - pooladdr->bus == defaddr->bus && - pooladdr->slot == defaddr->slot && - pooladdr->function == defaddr->function && - pool_scsi_host->unique_id == def_scsi_host->unique_id) - return true; - - return false; -} - - -static bool -virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc, - virStoragePoolSourcePtr defsrc) -{ - if (poolsrc->nhost != 1 && defsrc->nhost != 1) - return false; - - if (defsrc->hosts[0].port && - poolsrc->hosts[0].port != defsrc->hosts[0].port) - return false; - - return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name); -} - - -static bool -virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) -{ - virStoragePoolSourcePtr poolsrc = &obj->def->source; - virStoragePoolSourcePtr defsrc = &def->source; - - /* NB: Do not check the source host name */ - if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn)) - return false; - - return true; -} - - -static virStoragePoolObjPtr -virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) -{ - if (obj->def->type == VIR_STORAGE_POOL_DIR) { - if (STREQ(obj->def->target.path, def->target.path)) - return obj; - } else if (obj->def->type == VIR_STORAGE_POOL_GLUSTER) { - if (STREQ(obj->def->source.name, def->source.name) && - STREQ_NULLABLE(obj->def->source.dir, def->source.dir) && - virStoragePoolSourceMatchSingleHost(&obj->def->source, - &def->source)) - return obj; - } else if (obj->def->type == VIR_STORAGE_POOL_NETFS) { - if (STREQ(obj->def->source.dir, def->source.dir) && - virStoragePoolSourceMatchSingleHost(&obj->def->source, - &def->source)) - return obj; - } - - return NULL; -} - - -static virStoragePoolObjPtr -virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def, - virConnectPtr conn) -{ - virStorageAdapterPtr pool_adapter = &obj->def->source.adapter; - virStorageAdapterPtr def_adapter = &def->source.adapter; - virStorageAdapterSCSIHostPtr pool_scsi_host; - virStorageAdapterSCSIHostPtr def_scsi_host; - virStorageAdapterFCHostPtr pool_fchost; - virStorageAdapterFCHostPtr def_fchost; - unsigned int pool_hostnum; - unsigned int def_hostnum; - unsigned int scsi_hostnum; - - if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { - pool_fchost = &pool_adapter->data.fchost; - def_fchost = &def_adapter->data.fchost; - - if (STREQ(pool_fchost->wwnn, def_fchost->wwnn) && - STREQ(pool_fchost->wwpn, def_fchost->wwpn)) - return obj; - } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { - pool_scsi_host = &pool_adapter->data.scsi_host; - def_scsi_host = &def_adapter->data.scsi_host; - - if (pool_scsi_host->has_parent && - def_scsi_host->has_parent && - matchSCSIAdapterParent(pool_scsi_host, def_scsi_host)) - return obj; - - if (getSCSIHostNumber(pool_scsi_host, &pool_hostnum) < 0 || - getSCSIHostNumber(def_scsi_host, &def_hostnum) < 0) - return NULL; - if (pool_hostnum == def_hostnum) - return obj; - } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { - pool_fchost = &pool_adapter->data.fchost; - def_scsi_host = &def_adapter->data.scsi_host; - - /* Get the scsi_hostN for the scsi_host source adapter def */ - if (getSCSIHostNumber(def_scsi_host, &scsi_hostnum) < 0) - return NULL; - - if (matchFCHostToSCSIHost(conn, pool_fchost, scsi_hostnum)) - return obj; - - } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { - pool_scsi_host = &pool_adapter->data.scsi_host; - def_fchost = &def_adapter->data.fchost; - - if (getSCSIHostNumber(pool_scsi_host, &scsi_hostnum) < 0) - return NULL; - - if (matchFCHostToSCSIHost(conn, def_fchost, scsi_hostnum)) - return obj; - } - - return NULL; -} - - -static virStoragePoolObjPtr -virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) -{ - virStoragePoolObjPtr matchobj = NULL; - - if (obj->def->type == VIR_STORAGE_POOL_ISCSI) { - if (def->type != VIR_STORAGE_POOL_ISCSI) - return NULL; - - if ((matchobj = virStoragePoolSourceFindDuplicateDevices(obj, def))) { - if (!virStoragePoolSourceISCSIMatch(matchobj, def)) - return NULL; - } - return matchobj; - } - - if (def->type == VIR_STORAGE_POOL_ISCSI) - return NULL; - - /* VIR_STORAGE_POOL_FS - * VIR_STORAGE_POOL_LOGICAL - * VIR_STORAGE_POOL_DISK - * VIR_STORAGE_POOL_ZFS */ - return virStoragePoolSourceFindDuplicateDevices(obj, def); -} - - -struct _virStoragePoolObjFindDuplicateData { - virConnectPtr conn; - virStoragePoolDefPtr def; -}; - -static int -virStoragePoolObjSourceFindDuplicateCb(const void *payload, - const void *name ATTRIBUTE_UNUSED, - const void *opaque) -{ - virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload; - struct _virStoragePoolObjFindDuplicateData *data = - (struct _virStoragePoolObjFindDuplicateData *) opaque; - - /* Don't match against ourself if re-defining existing pool ! */ - if (STREQ(obj->def->name, data->def->name)) - return 0; - - switch ((virStoragePoolType)obj->def->type) { - case VIR_STORAGE_POOL_DIR: - case VIR_STORAGE_POOL_GLUSTER: - case VIR_STORAGE_POOL_NETFS: - if (data->def->type == obj->def->type && - virStoragePoolObjSourceMatchTypeDIR(obj, data->def)) - return 1; - break; - - case VIR_STORAGE_POOL_SCSI: - if (data->def->type == obj->def->type && - virStoragePoolObjSourceMatchTypeISCSI(obj, data->def, data->conn)) - return 1; - break; - - case VIR_STORAGE_POOL_ISCSI: - case VIR_STORAGE_POOL_ISCSI_DIRECT: - case VIR_STORAGE_POOL_FS: - case VIR_STORAGE_POOL_LOGICAL: - case VIR_STORAGE_POOL_DISK: - case VIR_STORAGE_POOL_ZFS: - if ((data->def->type == VIR_STORAGE_POOL_ISCSI || - data->def->type == VIR_STORAGE_POOL_ISCSI_DIRECT || - data->def->type == VIR_STORAGE_POOL_FS || - data->def->type == VIR_STORAGE_POOL_LOGICAL || - data->def->type == VIR_STORAGE_POOL_DISK || - data->def->type == VIR_STORAGE_POOL_ZFS) && - virStoragePoolObjSourceMatchTypeDEVICE(obj, data->def)) - return 1; - break; - - case VIR_STORAGE_POOL_SHEEPDOG: - if (data->def->type == obj->def->type && - virStoragePoolSourceMatchSingleHost(&obj->def->source, - &data->def->source)) - return 1; - break; - - case VIR_STORAGE_POOL_MPATH: - /* Only one mpath pool is valid per host */ - if (data->def->type == obj->def->type) - return 1; - break; - - case VIR_STORAGE_POOL_VSTORAGE: - if (data->def->type == obj->def->type && - STREQ(obj->def->source.name, data->def->source.name)) - return 1; - break; - - case VIR_STORAGE_POOL_RBD: - case VIR_STORAGE_POOL_LAST: - break; - } - - return 0; -} - - -int -virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, - virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def) -{ - struct _virStoragePoolObjFindDuplicateData data = { .conn = conn, - .def = def }; - virStoragePoolObjPtr obj = NULL; - - virObjectRWLockRead(pools); - obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb, - &data, NULL); - virObjectRWUnlock(pools); - - if (obj) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("Storage source conflict with pool: '%s'"), - obj->def->name); - return -1; - } - - return 0; -} - - #define MATCH(FLAG) (flags & (FLAG)) static bool virStoragePoolObjMatch(virStoragePoolObjPtr obj, -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
This function is going to be made static in used in virStoragePoolObjAssignDef(). Therefore move it and all the static functions it calls a few lines up.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 788 +++++++++++++++++++++++------------------------ 1 file changed, 394 insertions(+), 394 deletions(-)
Ugh, what a mess git diff makes... need some --patience on the diff Still consider my patch 3 suggestion about combining this with patch 2... It then just becomes a "reorganize the code" type patch where all the Add/Del, GetNum, GetName, and Export are lumped together. Either way, Reviewed-by: John Ferlan <jferlan@redhat.com> John

The @conn argument is needed only to do some source matching in case of iSCSI source. Anyway, it's used just for node device driver and as such can be replaced with virGetConnectNodeDev(). At the same time, the @conn struct member is dropped from _virStoragePoolObjFindDuplicateData. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 25 +++++++++++-------------- src/conf/virstorageobj.h | 3 +-- src/storage/storage_driver.c | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index b710ec652d..dce45ce870 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1169,7 +1169,6 @@ virStorageIsSameHostnum(const char *name, /* * matchFCHostToSCSIHost: * - * @conn: Connection pointer * @fchost: fc_host adapter ptr (either def or pool->def) * @scsi_hostnum: Already determined "scsi_pool" hostnum * @@ -1177,10 +1176,10 @@ virStorageIsSameHostnum(const char *name, * fc_adapter host# and the scsi_host host# */ static bool -matchFCHostToSCSIHost(virConnectPtr conn, - virStorageAdapterFCHostPtr fchost, +matchFCHostToSCSIHost(virStorageAdapterFCHostPtr fchost, unsigned int scsi_hostnum) { + virConnectPtr conn = NULL; bool ret = false; char *name = NULL; char *scsi_host_name = NULL; @@ -1211,7 +1210,8 @@ matchFCHostToSCSIHost(virConnectPtr conn, * If the parent fc_hostnum is the same as the scsi_hostnum, we * have a match. */ - if (conn && !fchost->parent) { + if (!fchost->parent && + (conn = virGetConnectNodeDev())) { if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) goto cleanup; if ((parent_name = virNodeDeviceGetParentName(conn, @@ -1240,6 +1240,7 @@ matchFCHostToSCSIHost(virConnectPtr conn, VIR_FREE(name); VIR_FREE(parent_name); VIR_FREE(scsi_host_name); + virConnectClose(conn); return ret; } @@ -1318,8 +1319,7 @@ virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj, static virStoragePoolObjPtr virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def, - virConnectPtr conn) + virStoragePoolDefPtr def) { virStorageAdapterPtr pool_adapter = &obj->def->source.adapter; virStorageAdapterPtr def_adapter = &def->source.adapter; @@ -1363,7 +1363,7 @@ virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, if (getSCSIHostNumber(def_scsi_host, &scsi_hostnum) < 0) return NULL; - if (matchFCHostToSCSIHost(conn, pool_fchost, scsi_hostnum)) + if (matchFCHostToSCSIHost(pool_fchost, scsi_hostnum)) return obj; } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && @@ -1374,7 +1374,7 @@ virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, if (getSCSIHostNumber(pool_scsi_host, &scsi_hostnum) < 0) return NULL; - if (matchFCHostToSCSIHost(conn, def_fchost, scsi_hostnum)) + if (matchFCHostToSCSIHost(def_fchost, scsi_hostnum)) return obj; } @@ -1411,7 +1411,6 @@ virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj, struct _virStoragePoolObjFindDuplicateData { - virConnectPtr conn; virStoragePoolDefPtr def; }; @@ -1439,7 +1438,7 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, case VIR_STORAGE_POOL_SCSI: if (data->def->type == obj->def->type && - virStoragePoolObjSourceMatchTypeISCSI(obj, data->def, data->conn)) + virStoragePoolObjSourceMatchTypeISCSI(obj, data->def)) return 1; break; @@ -1488,12 +1487,10 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, int -virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, - virStoragePoolObjListPtr pools, +virStoragePoolObjSourceFindDuplicate(virStoragePoolObjListPtr pools, virStoragePoolDefPtr def) { - struct _virStoragePoolObjFindDuplicateData data = { .conn = conn, - .def = def }; + struct _virStoragePoolObjFindDuplicateData data = {.def = def}; virStoragePoolObjPtr obj = NULL; virObjectRWLockRead(pools); diff --git a/src/conf/virstorageobj.h b/src/conf/virstorageobj.h index 9fabf34e4f..bc24db1928 100644 --- a/src/conf/virstorageobj.h +++ b/src/conf/virstorageobj.h @@ -246,8 +246,7 @@ virStoragePoolObjRemove(virStoragePoolObjListPtr pools, virStoragePoolObjPtr obj); int -virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, - virStoragePoolObjListPtr pools, +virStoragePoolObjSourceFindDuplicate(virStoragePoolObjListPtr pools, virStoragePoolDefPtr def); int diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 18a67ec8ac..df4f86c4bd 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -705,7 +705,7 @@ storagePoolCreateXML(virConnectPtr conn, if (virStoragePoolCreateXMLEnsureACL(conn, newDef) < 0) goto cleanup; - if (virStoragePoolObjSourceFindDuplicate(conn, driver->pools, newDef) < 0) + if (virStoragePoolObjSourceFindDuplicate(driver->pools, newDef) < 0) goto cleanup; if ((backend = virStorageBackendForType(newDef->type)) == NULL) @@ -796,7 +796,7 @@ storagePoolDefineXML(virConnectPtr conn, if (virStoragePoolDefineXMLEnsureACL(conn, newDef) < 0) goto cleanup; - if (virStoragePoolObjSourceFindDuplicate(conn, driver->pools, newDef) < 0) + if (virStoragePoolObjSourceFindDuplicate(driver->pools, newDef) < 0) goto cleanup; if (virStorageBackendForType(newDef->type) == NULL) -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
The @conn argument is needed only to do some source matching in case of iSCSI source. Anyway, it's used just for node device driver and as such can be replaced with virGetConnectNodeDev().
NB: Since commit 2870419eb enabled opening connections to secondary drivers at time of use, we no longer have to carry around the storage driver connection in order to use for the connection. (or something close to what commit decaeb28 describes)
At the same time, the @conn struct member is dropped from _virStoragePoolObjFindDuplicateData.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 25 +++++++++++-------------- src/conf/virstorageobj.h | 3 +-- src/storage/storage_driver.c | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com> John

Just like a few commits earlier, checking for pool source duplicates and unlocking pools list afterwards is a buggy pattern. The check must go into virStoragePoolObjAssignDef. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 7 ++++--- src/conf/virstorageobj.h | 4 ---- src/libvirt_private.syms | 1 - src/storage/storage_driver.c | 6 ------ 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index dce45ce870..c717176133 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1486,17 +1486,15 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, } -int +static int virStoragePoolObjSourceFindDuplicate(virStoragePoolObjListPtr pools, virStoragePoolDefPtr def) { struct _virStoragePoolObjFindDuplicateData data = {.def = def}; virStoragePoolObjPtr obj = NULL; - virObjectRWLockRead(pools); obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb, &data, NULL); - virObjectRWUnlock(pools); if (obj) { virReportError(VIR_ERR_OPERATION_FAILED, @@ -1531,6 +1529,9 @@ virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools, virObjectRWLockWrite(pools); + if (virStoragePoolObjSourceFindDuplicate(pools, def) < 0) + goto error; + rc = virStoragePoolObjIsDuplicate(pools, def, check_active, &obj); if (rc < 0) diff --git a/src/conf/virstorageobj.h b/src/conf/virstorageobj.h index bc24db1928..abd6166d88 100644 --- a/src/conf/virstorageobj.h +++ b/src/conf/virstorageobj.h @@ -245,10 +245,6 @@ void virStoragePoolObjRemove(virStoragePoolObjListPtr pools, virStoragePoolObjPtr obj); -int -virStoragePoolObjSourceFindDuplicate(virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def); - int virStoragePoolObjListExport(virConnectPtr conn, virStoragePoolObjListPtr poolobjs, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 572d1a1e22..e107efedcc 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1157,7 +1157,6 @@ virStoragePoolObjSetActive; virStoragePoolObjSetAutostart; virStoragePoolObjSetConfigFile; virStoragePoolObjSetDef; -virStoragePoolObjSourceFindDuplicate; virStoragePoolObjVolumeGetNames; virStoragePoolObjVolumeListExport; diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index df4f86c4bd..e7085e4773 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -705,9 +705,6 @@ storagePoolCreateXML(virConnectPtr conn, if (virStoragePoolCreateXMLEnsureACL(conn, newDef) < 0) goto cleanup; - if (virStoragePoolObjSourceFindDuplicate(driver->pools, newDef) < 0) - goto cleanup; - if ((backend = virStorageBackendForType(newDef->type)) == NULL) goto cleanup; @@ -796,9 +793,6 @@ storagePoolDefineXML(virConnectPtr conn, if (virStoragePoolDefineXMLEnsureACL(conn, newDef) < 0) goto cleanup; - if (virStoragePoolObjSourceFindDuplicate(driver->pools, newDef) < 0) - goto cleanup; - if (virStorageBackendForType(newDef->type) == NULL) goto cleanup; -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
Just like a few commits earlier, checking for pool source duplicates and unlocking pools list afterwards is a buggy pattern. The check must go into virStoragePoolObjAssignDef.
Probably should be noted that this also swaps the order of checking from pool name/uuid duplication, then pool source duplication to pool source, then pool name/uuid. In the long run it doesn't matter and this new order is fine. I assume the current order was chosen because it's quicker to HashLookup as opposed to HashSearch (although lately making assumptions hasn't necessarily worked out for me). Another change is now the duplication checks are held under a write lock instead of a concurrent read lock.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/conf/virstorageobj.c | 7 ++++--- src/conf/virstorageobj.h | 4 ---- src/libvirt_private.syms | 1 - src/storage/storage_driver.c | 6 ------ 4 files changed, 4 insertions(+), 14 deletions(-)
diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index dce45ce870..c717176133 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1486,17 +1486,15 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, }
-int +static int virStoragePoolObjSourceFindDuplicate(virStoragePoolObjListPtr pools, virStoragePoolDefPtr def)
Let's take the opportunity to rename this too virStoragePoolObjAssignIsDuplicatePoolSource Return true/false too... All can be done in the same patch. Reviewed-by: John Ferlan <jferlan@redhat.com> John

There are few operations in the storage driver that read/write data onto volumes. Such operations can take very long time to finish. During that time the storage pool object is locked which has bad performance impacts (other threads can't fetch its XML for instance). This commit prepares the storage driver for releasing the lock during those operations (downloadVol, uploadVol, wipeVol). Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_driver.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index e7085e4773..9edd5df119 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -2176,8 +2176,13 @@ storageVolDownload(virStorageVolPtr vol, goto cleanup; } - ret = backend->downloadVol(obj, voldef, stream, - offset, length, flags); + virStoragePoolObjIncrAsyncjobs(obj); + voldef->in_use++; + + ret = backend->downloadVol(obj, voldef, stream, offset, length, flags); + + voldef->in_use--; + virStoragePoolObjDecrAsyncjobs(obj); cleanup: virStoragePoolObjEndAPI(&obj); @@ -2326,6 +2331,7 @@ storageVolUpload(virStorageVolPtr vol, virStoragePoolDefPtr def; virStorageVolDefPtr voldef = NULL; virStorageVolStreamInfoPtr cbdata = NULL; + int rc; int ret = -1; virCheckFlags(VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM, -1); @@ -2370,8 +2376,15 @@ storageVolUpload(virStorageVolPtr vol, VIR_STRDUP(cbdata->vol_path, voldef->target.path) < 0) goto cleanup; - if ((ret = backend->uploadVol(obj, voldef, stream, - offset, length, flags)) < 0) + virStoragePoolObjIncrAsyncjobs(obj); + voldef->in_use++; + + rc = backend->uploadVol(obj, voldef, stream, offset, length, flags); + + voldef->in_use--; + virStoragePoolObjDecrAsyncjobs(obj); + + if (rc < 0) goto cleanup; /* Add cleanup callback - call after uploadVol since the stream @@ -2381,7 +2394,7 @@ storageVolUpload(virStorageVolPtr vol, virStorageVolFDStreamCloseCb, cbdata, NULL); cbdata = NULL; - + ret = 0; cleanup: virStoragePoolObjEndAPI(&obj); if (cbdata) @@ -2499,6 +2512,7 @@ storageVolWipePattern(virStorageVolPtr vol, virStorageBackendPtr backend; virStoragePoolObjPtr obj = NULL; virStorageVolDefPtr voldef = NULL; + int rc; int ret = -1; virCheckFlags(0, -1); @@ -2538,7 +2552,15 @@ storageVolWipePattern(virStorageVolPtr vol, goto cleanup; } - if (backend->wipeVol(obj, voldef, algorithm, flags) < 0) + virStoragePoolObjIncrAsyncjobs(obj); + voldef->in_use++; + + rc = backend->wipeVol(obj, voldef, algorithm, flags); + + voldef->in_use--; + virStoragePoolObjDecrAsyncjobs(obj); + + if (rc < 0) goto cleanup; /* Instead of using the refreshVol, since much changes on the target -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
There are few operations in the storage driver that read/write data onto volumes. Such operations can take very long time to finish. During that time the storage pool object is locked which has bad performance impacts (other threads can't fetch its XML for instance). This commit prepares the storage driver for releasing the lock during those operations (downloadVol, uploadVol, wipeVol).
The performance concurrency implications description could just be moved to the next patch instead of indicating there "As advertised". For this commit, noting that we are preparing for future release of the pool lock while one of the upload, download, or wipe volumes operations is occurring. This means adjusting the asyncJob count to inhibit pool operations that would be affected by the volume change from occurring while we're in the process of upload, download, or wipe of a volume and similarly adjusting the volume in_use count to inhibit other competing operations from occurring (or something really generic).
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_driver.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com> John

As advertised in previous commit, there are three APIs that might run for quite some time (because they read/write data from/to a volume) and these three are: downloadVol, uploadVol, wipeVol. Release pool object lock and reacquire it later to allow more concurrency. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_iscsi_direct.c | 6 +++++- src/storage/storage_backend_rbd.c | 8 ++++++-- src/storage/storage_driver.c | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c index 0d7d6ba9c3..5c1b251a17 100644 --- a/src/storage/storage_backend_iscsi_direct.c +++ b/src/storage/storage_backend_iscsi_direct.c @@ -693,7 +693,11 @@ virStorageBackenISCSIDirectWipeVol(virStoragePoolObjPtr pool, virCheckFlags(0, -1); - if (!(iscsi = virStorageBackendISCSIDirectSetConnection(pool, NULL))) + virObjectLock(pool); + iscsi = virStorageBackendISCSIDirectSetConnection(pool, NULL); + virObjectUnlock(pool); + + if (!iscsi) return -1; switch ((virStorageVolWipeAlgorithm) algorithm) { diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index c6fb791a81..2cba678b72 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -1200,7 +1200,7 @@ virStorageBackendRBDVolWipe(virStoragePoolObjPtr pool, unsigned int flags) { virStorageBackendRBDStatePtr ptr = NULL; - virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + virStoragePoolDefPtr def; rbd_image_t image = NULL; rbd_image_info_t info; uint64_t stripe_count; @@ -1209,9 +1209,13 @@ virStorageBackendRBDVolWipe(virStoragePoolObjPtr pool, virCheckFlags(0, -1); + virObjectLock(pool); + def = virStoragePoolObjGetDef(pool); VIR_DEBUG("Wiping RBD image %s/%s", def->source.name, vol->name); + ptr = virStorageBackendRBDNewState(pool); + virObjectUnlock(pool); - if (!(ptr = virStorageBackendRBDNewState(pool))) + if (!ptr) goto cleanup; if ((r = rbd_open(ptr->ioctx, vol->name, &image, NULL)) < 0) { diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 9edd5df119..8943df1f84 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -2178,9 +2178,11 @@ storageVolDownload(virStorageVolPtr vol, virStoragePoolObjIncrAsyncjobs(obj); voldef->in_use++; + virObjectUnlock(obj); ret = backend->downloadVol(obj, voldef, stream, offset, length, flags); + virObjectLock(obj); voldef->in_use--; virStoragePoolObjDecrAsyncjobs(obj); @@ -2378,9 +2380,11 @@ storageVolUpload(virStorageVolPtr vol, virStoragePoolObjIncrAsyncjobs(obj); voldef->in_use++; + virObjectUnlock(obj); rc = backend->uploadVol(obj, voldef, stream, offset, length, flags); + virObjectLock(obj); voldef->in_use--; virStoragePoolObjDecrAsyncjobs(obj); @@ -2554,9 +2558,11 @@ storageVolWipePattern(virStorageVolPtr vol, virStoragePoolObjIncrAsyncjobs(obj); voldef->in_use++; + virObjectUnlock(obj); rc = backend->wipeVol(obj, voldef, algorithm, flags); + virObjectLock(obj); voldef->in_use--; virStoragePoolObjDecrAsyncjobs(obj); -- 2.16.4

On 08/20/2018 08:09 AM, Michal Privoznik wrote:
As advertised in previous commit, there are three APIs that might run for quite some time (because they read/write data from/to a volume) and these three are: downloadVol, uploadVol, wipeVol. Release pool object lock and reacquire it later to allow more concurrency.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_iscsi_direct.c | 6 +++++- src/storage/storage_backend_rbd.c | 8 ++++++-- src/storage/storage_driver.c | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-)
I think we could/should note in src/storage/storage_backend.h that for the three functions (Download, Upload, and Wipe) that upon entry the @obj for the pool is unlocked, but the pool object's "asyncjobs" will be adjusted to allow concurrency and that the the volume's "in_use" adjusted to ensure singular usage. I'd also add a similar comment to virStorageBackendVolWipeLocal, virStorageBackendDiskVolWipe, virStorageBackendVolUploadLocal, and virStorageBackendVoldownloadLocal that the @pool is unlocked prior to the call. If virStorageBackendRBDVolWipe or virStorageBackenISCSIDirectWipeVol get a similar information is up to you, I'd probably put it there too just for completeness for the "next" poor soul that copies from one of the existing backends. Whether or not anyone actually reads it is their problem, at least we noted it! Reviewed-by: John Ferlan <jferlan@redhat.com> John FWIW: I almost had an oh sh*t moment with virObject{Unlock|Lock} before I came back in off the ledge since we're not talking the pools' rwlock, but the pool's obj/def lock that isn't an rwlock.

On 08/28/2018 08:36 PM, John Ferlan wrote:
On 08/20/2018 08:09 AM, Michal Privoznik wrote:
As advertised in previous commit, there are three APIs that might run for quite some time (because they read/write data from/to a volume) and these three are: downloadVol, uploadVol, wipeVol. Release pool object lock and reacquire it later to allow more concurrency.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/storage/storage_backend_iscsi_direct.c | 6 +++++- src/storage/storage_backend_rbd.c | 8 ++++++-- src/storage/storage_driver.c | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-)
I think we could/should note in src/storage/storage_backend.h that for the three functions (Download, Upload, and Wipe) that upon entry the @obj for the pool is unlocked, but the pool object's "asyncjobs" will be adjusted to allow concurrency and that the the volume's "in_use" adjusted to ensure singular usage.
I'd also add a similar comment to virStorageBackendVolWipeLocal, virStorageBackendDiskVolWipe, virStorageBackendVolUploadLocal, and virStorageBackendVoldownloadLocal that the @pool is unlocked prior to the call.
If virStorageBackendRBDVolWipe or virStorageBackenISCSIDirectWipeVol get a similar information is up to you, I'd probably put it there too just for completeness for the "next" poor soul that copies from one of the existing backends.
Whether or not anyone actually reads it is their problem, at least we noted it!
Reviewed-by: John Ferlan <jferlan@redhat.com>
Thanks, I've done all the changes you requested in my local branch. I'll wait until the release to push these though. Michal
participants (2)
-
John Ferlan
-
Michal Privoznik