diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in
index 9d77c452c93f7417f9ec48afdf62444875fd1022..29c193108f407bdb50ede47d489b371797b31ae2 100644
--- a/docs/formatstorage.html.in
+++ b/docs/formatstorage.html.in
@@ -190,6 +190,19 @@
defined for an existing scsi_host or by creating a vHBA.
Since 1.0.4
+
managed
+
An optional attribute to instruct the SCSI storage backend to
+ manage destroying the vHBA when the pool is destroyed. For
+ configurations that do not provide an already created vHBA
+ from a 'virsh nodedev-create', libvirt will set this property
+ to "yes". For configurations that have already created a vHBA
+ via 'virsh nodedev-create' and are using the wwnn/wwpn from
+ that vHBA and optionally the scsi_host parent, setting this
+ attribute to "yes" will allow libvirt to destroy the node device
+ when the pool is destroyed. If this attribute is set to "no" or
+ not defined in the XML, then libvirt will not destroy the vHBA.
+ Since 1.2.11
+
parentaddr
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 14245c9a6ffa3e2d5eba3706197c40a4693c2656..9ddd92b5f1fc7458d1bf73f3b8200186f0d91537 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -389,6 +389,11 @@
+
+
+
+
+
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 4126451c3b522630c4a4ab9e43d9a8ee0e547495..1251b4785dbd41c0b0775030934515ac425eca16 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -475,6 +475,7 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
char *name = NULL;
char *port = NULL;
char *adapter_type = NULL;
+ char *managed = NULL;
int n;
relnode = ctxt->node;
@@ -578,6 +579,18 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
source->adapter.data.fchost.parent =
virXPathString("string(./adapter/@parent)", ctxt);
+ managed = virXPathString("string(./adapter/@managed)", ctxt);
+ if (managed) {
+ source->adapter.data.fchost.managed =
+ virTristateBoolTypeFromString(managed);
+ if (source->adapter.data.fchost.managed < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown fc_host managed setting '%s'"),
+ managed);
+ goto cleanup;
+ }
+ }
+
source->adapter.data.fchost.wwnn =
virXPathString("string(./adapter/@wwnn)", ctxt);
source->adapter.data.fchost.wwpn =
@@ -675,6 +688,7 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
VIR_FREE(port);
VIR_FREE(nodeset);
VIR_FREE(adapter_type);
+ VIR_FREE(managed);
virStorageAuthDefFree(authdef);
return ret;
}
@@ -1076,6 +1090,9 @@ virStoragePoolSourceFormat(virBufferPtr buf,
if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
virBufferEscapeString(buf, " parent='%s'",
src->adapter.data.fchost.parent);
+ if (src->adapter.data.fchost.managed)
+ virBufferAsprintf(buf, " managed='%s'",
+ virTristateBoolTypeToString(src->adapter.data.fchost.managed));
virBufferAsprintf(buf, " wwnn='%s' wwpn='%s'/>\n",
src->adapter.data.fchost.wwnn,
src->adapter.data.fchost.wwpn);
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 67145a00b651dfccdf4b2e9d01f46fa67132557b..765f681d0aa8c57914a955efe7187f4731b4d8c9 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -192,6 +192,7 @@ struct _virStoragePoolSourceAdapter {
char *parent;
char *wwnn;
char *wwpn;
+ int managed; /* enum virTristateSwitch */
} fchost;
} data;
};
diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c
index a5bb85f5fc07b2783eef464afe26ed2ab22fd860..3f61610c3430ab0039992e2b0ef8f35cebf32459 100644
--- a/src/storage/storage_backend_scsi.c
+++ b/src/storage/storage_backend_scsi.c
@@ -590,6 +590,9 @@ getVhbaSCSIHostParent(virConnectPtr conn,
if (!(def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL)))
goto cleanup;
+ /* The caller checks whether the returned value is NULL or not
+ * before continuing
+ */
ignore_value(VIR_STRDUP(vhba_parent, def->parent));
cleanup:
@@ -644,15 +647,21 @@ checkVhbaSCSIHostParent(virConnectPtr conn,
static int
createVport(virConnectPtr conn,
+ const char *configFile,
virStoragePoolDefPtr def)
{
virStoragePoolSourceAdapterPtr adapter = &def->source.adapter;
unsigned int parent_host;
char *name = NULL;
+ char *parent_hoststr = NULL;
if (adapter->type != VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST)
return 0;
+ VIR_DEBUG("conn=%p, configFile='%s' parent='%s', wwnn='%s' wwpn='%s'",
+ conn, NULLSTR(configFile), NULLSTR(adapter->data.fchost.parent),
+ adapter->data.fchost.wwnn, adapter->data.fchost.wwpn);
+
/* If a parent was provided, then let's make sure it's vhost capable */
if (adapter->data.fchost.parent) {
if (virGetSCSIHostNumber(adapter->data.fchost.parent, &parent_host) < 0)
@@ -687,15 +696,40 @@ createVport(virConnectPtr conn,
}
if (!adapter->data.fchost.parent) {
- if (!(adapter->data.fchost.parent = virFindFCHostCapableVport(NULL))) {
+ if (!(parent_hoststr = virFindFCHostCapableVport(NULL))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("'parent' for vHBA not specified, and "
"cannot find one on this host"));
return -1;
}
- if (virGetSCSIHostNumber(adapter->data.fchost.parent, &parent_host) < 0)
+ if (virGetSCSIHostNumber(parent_hoststr, &parent_host) < 0) {
+ VIR_FREE(parent_hoststr);
return -1;
+ }
+
+ /* NOTE:
+ * We do not save the parent_hoststr in adapter->data.fchost.parent
+ * since we could be writing out the 'def' to the saved XML config.
+ * If we wrote out the name in the XML, then future starts would
+ * always use the same parent rather than finding the "best available"
+ * parent. Besides we have a way to determine the parent based on
+ * the 'name' field.
+ */
+ VIR_FREE(parent_hoststr);
+ }
+
+ /* Since we're creating the vHBA, then we need to manage removing it
+ * as well. Since we need this setting to "live" through a libvirtd
+ * restart, we need to save the persistent configuration. So if not
+ * already defined as YES, then force the issue.
+ */
+ if (adapter->data.fchost.managed != VIR_TRISTATE_BOOL_YES) {
+ adapter->data.fchost.managed = VIR_TRISTATE_BOOL_YES;
+ if (configFile) {
+ if (virStoragePoolSaveConfig(configFile, def) < 0)
+ return -1;
+ }
}
if (virManageVport(parent_host, adapter->data.fchost.wwpn,
@@ -707,29 +741,50 @@ createVport(virConnectPtr conn,
}
static int
-deleteVport(virStoragePoolSourceAdapter adapter)
+deleteVport(virConnectPtr conn,
+ virStoragePoolSourceAdapter adapter)
{
unsigned int parent_host;
char *name = NULL;
+ char *vhba_parent = NULL;
int ret = -1;
if (adapter.type != VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST)
return 0;
- /* It must be a HBA instead of a vHBA as long as "parent"
- * is NULL. "createVport" guaranteed "parent" for a vHBA
- * cannot be NULL, it's either specified in XML, or detected
- * automatically.
- */
- if (!adapter.data.fchost.parent)
+ VIR_DEBUG("conn=%p parent='%s', managed='%d' wwnn='%s' wwpn='%s'",
+ conn, NULLSTR(adapter.data.fchost.parent),
+ adapter.data.fchost.managed,
+ adapter.data.fchost.wwnn,
+ adapter.data.fchost.wwpn);
+
+ /* If we're not managing the deletion of the vHBA, then just return */
+ if (adapter.data.fchost.managed != VIR_TRISTATE_BOOL_YES)
return 0;
+ /* Find our vHBA by searching the fc_host sysfs tree for our wwnn/wwpn */
if (!(name = virGetFCHostNameByWWN(NULL, adapter.data.fchost.wwnn,
- adapter.data.fchost.wwpn)))
- return -1;
-
- if (virGetSCSIHostNumber(adapter.data.fchost.parent, &parent_host) < 0)
+ adapter.data.fchost.wwpn))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to find fc_host for wwnn='%s' and wwpn='%s'"),
+ adapter.data.fchost.wwnn, adapter.data.fchost.wwpn);
goto cleanup;
+ }
+
+ /* If at startup time we provided a parent, then use that to
+ * get the parent_host value; otherwise, we have to determine
+ * the parent scsi_host which we did not save at startup time
+ */
+ if (adapter.data.fchost.parent) {
+ if (virGetSCSIHostNumber(adapter.data.fchost.parent, &parent_host) < 0)
+ goto cleanup;
+ } else {
+ if (!(vhba_parent = getVhbaSCSIHostParent(conn, name)))
+ goto cleanup;
+
+ if (virGetSCSIHostNumber(vhba_parent, &parent_host) < 0)
+ goto cleanup;
+ }
if (virManageVport(parent_host, adapter.data.fchost.wwpn,
adapter.data.fchost.wwnn, VPORT_DELETE) < 0)
@@ -738,6 +793,7 @@ deleteVport(virStoragePoolSourceAdapter adapter)
ret = 0;
cleanup:
VIR_FREE(name);
+ VIR_FREE(vhba_parent);
return ret;
}
@@ -817,15 +873,15 @@ static int
virStorageBackendSCSIStartPool(virConnectPtr conn,
virStoragePoolObjPtr pool)
{
- return createVport(conn, pool->def);
+ return createVport(conn, pool->configFile, pool->def);
}
static int
-virStorageBackendSCSIStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+virStorageBackendSCSIStopPool(virConnectPtr conn,
virStoragePoolObjPtr pool)
{
virStoragePoolSourceAdapter adapter = pool->def->source.adapter;
- return deleteVport(adapter);
+ return deleteVport(conn, adapter);
}
virStorageBackend virStorageBackendSCSI = {
diff --git a/tests/storagepoolxml2xmlin/pool-scsi-type-fc-host-managed.xml b/tests/storagepoolxml2xmlin/pool-scsi-type-fc-host-managed.xml
new file mode 100644
index 0000000000000000000000000000000000000000..43611eecfb680dcc4315eb3b3bde196736032311
--- /dev/null
+++ b/tests/storagepoolxml2xmlin/pool-scsi-type-fc-host-managed.xml
@@ -0,0 +1,15 @@
+
+ hba0
+ e9392370-2917-565e-692b-d057f46512d6
+
+
+ /dev/disk/by-path
+
+ 0700
+ 0
+ 0
+
+
+
diff --git a/tests/storagepoolxml2xmlout/pool-scsi-type-fc-host-managed.xml b/tests/storagepoolxml2xmlout/pool-scsi-type-fc-host-managed.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c8bb0db9e092660894f15a8afd7d71108eff6610
--- /dev/null
+++ b/tests/storagepoolxml2xmlout/pool-scsi-type-fc-host-managed.xml
@@ -0,0 +1,18 @@
+
+ hba0
+ e9392370-2917-565e-692b-d057f46512d6
+ 0
+ 0
+ 0
+
+
+ /dev/disk/by-path
+
+ 0700
+ 0
+ 0
+
+
+
diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c
index 8a2c0b50a13d22c2594fcfd5b09dc5b8f16895c2..52e2193e8392443c26b1c6c7dfb5a65a0142d4d2 100644
--- a/tests/storagepoolxml2xmltest.c
+++ b/tests/storagepoolxml2xmltest.c
@@ -98,6 +98,7 @@ mymain(void)
DO_TEST("pool-scsi");
DO_TEST("pool-scsi-type-scsi-host");
DO_TEST("pool-scsi-type-fc-host");
+ DO_TEST("pool-scsi-type-fc-host-managed");
DO_TEST("pool-mpath");
DO_TEST("pool-iscsi-multiiqn");
DO_TEST("pool-iscsi-vendor-product");