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");