diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index 29c193108f..de786b874c 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -157,6 +157,25 @@ compatibility, this attribute is optional only for the "scsi_host" adapter, but is mandatory for the "fc_host" adapter. Since 1.0.5 + A "fc_host" capable scsi_hostN can be determined by using + virsh nodedev-list --cap fc_host. + Since 1.2.8 +

+ Note: Regardless of whether a "scsi_host" adapter type is defined + using a name or a parentaddr, it + should refer to a real scsi_host adapter as found through a + virsh nodedev-list scsi_host and virsh + nodedev-dumpxml scsi_hostN on one of the scsi_host's + displayed. It should not refer to a "fc_host" capable scsi_hostN + nor should it refer to the vHBA created for some "fc_host" + adapter. For a vHBA the nodedev-dumpxml + output parent setting will be the "fc_host" capable scsi_hostN + value. Additionally, do not refer to an iSCSI scsi_hostN for the + "scsi_host" source. An iSCSI scsi_hostN's + nodedev-dumpxml output parent field is generally + "computer". This is a libvirt created parent value indicating + no parent was defined for the node device. +

@@ -187,7 +206,12 @@ the vHBA created by 'virsh nodedev-create', rather it is the parent of that vHBA. If the value is not provided, libvirt will determine the parent based either finding the wwnn,wwpn - defined for an existing scsi_host or by creating a vHBA. + defined for an existing scsi_host or by creating a vHBA. Providing + the parent attribute is also useful for the duplicate pool + definition checks. This is more important in environments where + both the "fc_host" and "scsi_host" source adapter pools are being + used in order to ensure a new definition doesn't duplicate using + the scsi_hostN of some existing storage pool. Since 1.0.4
managed
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index a76d48a26c..f75e862e0d 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -2169,6 +2169,83 @@ getSCSIHostNumber(virStoragePoolSourceAdapter adapter, VIR_FREE(name); return ret; } + +/* + * matchFCHostToSCSIHost: + * + * @conn: Connection pointer + * @fc_adapter: fc_host adapter (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, + virStoragePoolSourceAdapter fc_adapter, + unsigned int scsi_hostnum) +{ + char *name = NULL; + char *parent_name = NULL; + unsigned int fc_hostnum; + + /* If we have a parent defined, get it's hostnum, and compare to the + * scsi_hostnum. If they are the same, then we have a match + */ + if (fc_adapter.data.fchost.parent && + virGetSCSIHostNumber(fc_adapter.data.fchost.parent, &fc_hostnum) == 0 && + scsi_hostnum == fc_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 = virGetFCHostNameByWWN(NULL, fc_adapter.data.fchost.wwnn, + fc_adapter.data.fchost.wwpn))) { + + /* Get the scsi_hostN for the vHBA in order to see if it + * matches our scsi_hostnum + */ + if (virGetSCSIHostNumber(name, &fc_hostnum) == 0 && + scsi_hostnum == fc_hostnum) { + VIR_FREE(name); + return true; + } + + /* 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 && !fc_adapter.data.fchost.parent) { + parent_name = virStoragePoolGetVhbaSCSIHostParent(conn, name); + if (parent_name) { + if (virGetSCSIHostNumber(parent_name, &fc_hostnum) == 0 && + scsi_hostnum == fc_hostnum) { + VIR_FREE(parent_name); + VIR_FREE(name); + return true; + } + VIR_FREE(parent_name); + } else { + /* Throw away the error and fall through */ + virResetLastError(); + VIR_DEBUG("Could not determine parent vHBA"); + } + } + VIR_FREE(name); + } + + /* 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. + */ + return false; +} + static bool matchSCSIAdapterParent(virStoragePoolObjPtr pool, virStoragePoolDefPtr def) @@ -2193,7 +2270,8 @@ matchSCSIAdapterParent(virStoragePoolObjPtr pool, int -virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools, +virStoragePoolSourceFindDuplicate(virConnectPtr conn, + virStoragePoolObjListPtr pools, virStoragePoolDefPtr def) { size_t i; @@ -2253,6 +2331,38 @@ virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools, break; if (pool_hostnum == def_hostnum) matchpool = pool; + } else if (pool->def->source.adapter.type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST && + def->source.adapter.type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) { + unsigned int scsi_hostnum; + + /* Get the scsi_hostN for the scsi_host source adapter def */ + if (getSCSIHostNumber(def->source.adapter, + &scsi_hostnum) < 0) + break; + + if (matchFCHostToSCSIHost(conn, pool->def->source.adapter, + scsi_hostnum)) { + matchpool = pool; + break; + } + + } else if (pool->def->source.adapter.type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST && + def->source.adapter.type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { + unsigned int scsi_hostnum; + + if (getSCSIHostNumber(pool->def->source.adapter, + &scsi_hostnum) < 0) + break; + + if (matchFCHostToSCSIHost(conn, def->source.adapter, + scsi_hostnum)) { + matchpool = pool; + break; + } } break; case VIR_STORAGE_POOL_ISCSI: diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 228bb1c39e..2c9eaedebc 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -394,7 +394,8 @@ char *virStoragePoolGetVhbaSCSIHostParent(virConnectPtr conn, const char *name) ATTRIBUTE_NONNULL(1); -int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools, +int virStoragePoolSourceFindDuplicate(virConnectPtr conn, + virStoragePoolObjListPtr pools, virStoragePoolDefPtr def); void virStoragePoolObjLock(virStoragePoolObjPtr obj); diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c index e1b6ea89ee..4a16325dc0 100644 --- a/src/parallels/parallels_storage.c +++ b/src/parallels/parallels_storage.c @@ -719,7 +719,7 @@ parallelsStoragePoolDefineXML(virConnectPtr conn, if (virStoragePoolObjIsDuplicate(&privconn->pools, def, 0) < 0) goto cleanup; - if (virStoragePoolSourceFindDuplicate(&privconn->pools, def) < 0) + if (virStoragePoolSourceFindDuplicate(conn, &privconn->pools, def) < 0) goto cleanup; if (parallelsStoragePoolGetAlloc(def)) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 23b63f540e..88dea3457a 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -610,7 +610,7 @@ storagePoolCreateXML(virConnectPtr conn, if (virStoragePoolObjIsDuplicate(&driver->pools, def, 1) < 0) goto cleanup; - if (virStoragePoolSourceFindDuplicate(&driver->pools, def) < 0) + if (virStoragePoolSourceFindDuplicate(conn, &driver->pools, def) < 0) goto cleanup; if ((backend = virStorageBackendForType(def->type)) == NULL) @@ -669,7 +669,7 @@ storagePoolDefineXML(virConnectPtr conn, if (virStoragePoolObjIsDuplicate(&driver->pools, def, 0) < 0) goto cleanup; - if (virStoragePoolSourceFindDuplicate(&driver->pools, def) < 0) + if (virStoragePoolSourceFindDuplicate(conn, &driver->pools, def) < 0) goto cleanup; if (virStorageBackendForType(def->type) == NULL)