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)