Daniel P. Berrange wrote:
On Tue, Apr 07, 2009 at 05:16:31PM -0400, David Allan wrote:
>
> static int
> +virStorageBackendVportCreateDelete(virConnectPtr conn,
> + virStoragePoolObjPtr pool,
> + int operation)
> +{
> + int fd = -1;
> + int retval = 0;
> + char *operation_path;
> + const char *operation_file;
> + char *vport_name;
> + size_t towrite = 0;
> +
> + switch (operation) {
> + case VPORT_CREATE:
> + operation_file = LINUX_SYSFS_VPORT_CREATE_POSTFIX;
> + break;
> + case VPORT_DELETE:
> + operation_file = LINUX_SYSFS_VPORT_DELETE_POSTFIX;
> + break;
> + default:
> + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
> + _("Invalid vport operation (%d)"),
operation);
> + retval = -1;
> + goto no_unwind;
> + break;
> + }
> +
> + if (virAsprintf(&operation_path,
> + "%s/%s/%s",
> + LINUX_SYSFS_FC_HOST_PREFIX,
> + pool->def->source.adapter,
> + operation_file) < 0) {
> +
> + virReportOOMError(conn);
> + retval = -1;
> + goto no_unwind;
> + }
> +
> + VIR_DEBUG(_("Vport operation path is '%s'"), operation_path);
> +
> + fd = open(operation_path, O_WRONLY);
> +
> + if (fd < 0) {
> + virReportSystemError(conn, errno,
> + _("Could not open '%s' for vport
operation"),
> + operation_path);
> + retval = -1;
> + goto free_path;
> + }
> +
> + if (virAsprintf(&vport_name,
> + "%s:%s",
> + pool->def->source.wwpn,
> + pool->def->source.wwnn) < 0) {
> +
> + virReportOOMError(conn);
> + retval = -1;
> + goto close_fd;
> + }
> +
> + towrite = sizeof(vport_name);
> + if (safewrite(fd, vport_name, towrite) != towrite) {
> + virReportSystemError(conn, errno,
> + _("Write of '%s' to '%s' during
"
> + "vport create/delete failed"),
> + vport_name, operation_path);
> + retval = -1;
> + }
This chunk of code could be a little simplified by making it
call out to virFileWriteStr() from src/util.h
Thanks for the pointer--I'll make that change.
> +
> + VIR_FREE(vport_name);
> +close_fd:
> + close(fd);
> +free_path:
> + VIR_FREE(operation_path);
> +no_unwind:
> + VIR_DEBUG("%s", _("Vport operation complete"));
> + return retval;
> +}
> +
> +
> +static int
> +virStorageBackendSCSIStartPool(virConnectPtr conn,
> + virStoragePoolObjPtr pool)
> +{
> + int retval = 0;
> +
> + if (pool->def->source.wwnn != NULL) {
> + retval = virStorageBackendVportCreateDelete(conn, pool, VPORT_CREATE);
> + }
> +
> + return retval;
> +}
> +
> +
> +static int
> +virStorageBackendSCSIStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
> + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
> +{
> + int retval = 0;
> +
> + if (pool->def->source.wwnn != NULL) {
> + retval = virStorageBackendVportCreateDelete(conn, pool, VPORT_DELETE);
> + }
> +
> + return retval;
> +}
> +
> +
> +static int
> virStorageBackendSCSITriggerRescan(virConnectPtr conn,
> uint32_t host)
> {
> int fd = -1;
> int retval = 0;
> char *path;
> + size_t towrite = 0;
>
> VIR_DEBUG(_("Triggering rescan of host %d"), host);
>
> @@ -593,9 +702,8 @@ virStorageBackendSCSITriggerRescan(virConnectPtr conn,
> goto free_path;
> }
>
> - if (safewrite(fd,
> - LINUX_SYSFS_SCSI_HOST_SCAN_STRING,
> - sizeof(LINUX_SYSFS_SCSI_HOST_SCAN_STRING)) < 0) {
> + towrite = sizeof(LINUX_SYSFS_SCSI_HOST_SCAN_STRING);
> + if (safewrite(fd, LINUX_SYSFS_SCSI_HOST_SCAN_STRING, towrite) != towrite) {
>
> virReportSystemError(conn, errno,
> _("Write to '%s' to trigger host scan
failed"),
> @@ -645,5 +753,7 @@ out:
> virStorageBackend virStorageBackendSCSI = {
> .type = VIR_STORAGE_POOL_SCSI,
>
> + .startPool = virStorageBackendSCSIStartPool,
> .refreshPool = virStorageBackendSCSIRefreshPool,
> + .stopPool = virStorageBackendSCSIStopPool,
As per the previous mail, I think these are better switched over to the
.buildPool and .deletePool drivers.
> diff --git a/src/storage_conf.c b/src/storage_conf.c
> index 9e25ccb..4827d69 100644
> --- a/src/storage_conf.c
> +++ b/src/storage_conf.c
> @@ -42,6 +42,7 @@
> #include "buf.h"
> #include "util.h"
> #include "memory.h"
> +#include "logging.h"
>
> #define VIR_FROM_THIS VIR_FROM_STORAGE
>
> @@ -451,6 +452,55 @@ error:
> }
>
>
> +static int
> +getNPIVParameters(virConnectPtr conn,
> + virStoragePoolDefPtr pool,
> + xmlXPathContextPtr ctxt)
> +{
> + int retval = 0;
> +
> + if ((pool->source.wwpn = virXPathString(conn,
> +
"string(/pool/source/adapter/@wwpn)",
> + ctxt)) == NULL) {
> + VIR_DEBUG("%s", _("No WWPN found"));
> + goto out;
> + }
> +
> + VIR_DEBUG(_("Found WWPN '%s'"), pool->source.wwpn);
> +
> + if ((pool->source.wwnn = virXPathString(conn,
> +
"string(/pool/source/adapter/@wwnn)",
> + ctxt)) == NULL) {
> + VIR_DEBUG("%s", _("No WWNN found"));
> + goto out;
> + }
> +
> + VIR_DEBUG(_("Found WWNN '%s'"), pool->source.wwnn);
> +
> + if (pool->source.wwpn != NULL || pool->source.wwnn != NULL) {
> + if (pool->source.wwpn == NULL || pool->source.wwnn == NULL) {
> + virStorageReportError(conn, VIR_ERR_XML_ERROR,
> + _("Both WWPN and WWNN must be specified
"
> + "if either is specified"));
> + retval = -1;
> + goto cleanup;
> + }
> + }
> +
> + /* We don't check the values for validity, because the kernel does
> + * that. Any invalid values will be rejected when the pool
> + * starts. The kernel has the final say on what it will accept
> + * and we should not second guess it. */
> +
> +cleanup:
> + VIR_FREE(pool->source.wwpn);
> + VIR_FREE(pool->source.wwnn);
> +
> +out:
> + return retval;
> +}
> +
> +
> static virStoragePoolDefPtr
> virStoragePoolDefParseDoc(virConnectPtr conn,
> xmlXPathContextPtr ctxt,
> @@ -590,6 +640,9 @@ virStoragePoolDefParseDoc(virConnectPtr conn,
> "%s", _("missing storage pool source
adapter name"));
> goto cleanup;
> }
> + if (getNPIVParameters(conn, ret, ctxt) < 0) {
> + goto cleanup;
> + }
> }
>
> authType = virXPathString(conn, "string(/pool/source/auth/@type)",
ctxt);
> diff --git a/src/storage_conf.h b/src/storage_conf.h
> index 4e35ccb..cfd8b14 100644
> --- a/src/storage_conf.h
> +++ b/src/storage_conf.h
> @@ -192,6 +192,12 @@ struct _virStoragePoolSource {
> /* Or an adapter */
> char *adapter;
>
> + /* And an optional WWPN */
> + char *wwpn;
> +
> + /* And an optional WWNN */
> + char *wwnn;
> +
Since adapter, wwpn and wwnn are all associated with each other, I
think we should put them all into a union here. eg, replace the
current
char *adapter;
with
union {
char *name;
char *wwpn;
char *wwnn;
} adapter;
I don't have completely working code yet, but here's what I'm thinking:
We can't use a union because wwpn and wwnn will always be in use at the
same time, but I agree that we're starting to collect a bunch of related
information about adapters that clutters up the pool source struct.
I've created a struct along the lines of virStoragePoolSourceHost to
contain this information. It will need some additional fields.
/*
* For adapter based pools, info on the relevant adapter
*/
typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter;
typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr;
struct _virStoragePoolSourceAdapter {
char *name;
char *wwpn;
char *wwnn;
};
Since we might be creating a virtual adapter on a physical adapter that
we specify by wwpn/wwnn, we'll need two places to specify wwpn/wwnn in
the XML. I propose:
<pool type="scsi">
<name>npiv</name>
<source>
<adapter name="host6" wwpn="0000111122223333"
wwnn="4444555566667777"/>
<vport wwpn="88889999aaaabbbb" wwnn="ccccddddeeeeffff"/>
</source>
<target>
<path>/dev/disk/by-id</path>
</target>
</pool>
Dave