[libvirt] [PATCH 1/2] Backend of node device API NPIV support

Daniel Veillard veillard at redhat.com
Thu May 14 10:22:52 UTC 2009


On Fri, May 08, 2009 at 05:41:08PM -0400, David Allan wrote:
> +/* Caller must hold the driver lock. */
> +static virNodeDevicePtr
> +nodeDeviceLookupByWWN(virConnectPtr conn,
> +                      const char *wwnn,
> +                      const char *wwpn)
> +{
> +    unsigned int i, found = 0;
> +    virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
> +    virNodeDeviceObjListPtr devs = &driver->devs;
> +    virNodeDevCapsDefPtr cap = NULL;
> +    virNodeDeviceObjPtr obj = NULL;
> +    virNodeDevicePtr dev = NULL;
> +
> +    for (i = 0; i < devs->count; i++) {
> +
> +        obj = devs->objs[i];
> +        virNodeDeviceObjLock(obj);
> +        cap = obj->def->caps;
> +
> +        while (cap) {
> +
> +            if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
> +                if (cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
> +                    if (STREQ(cap->data.scsi_host.wwnn, wwnn) &&
> +                        STREQ(cap->data.scsi_host.wwpn, wwpn)) {

  I would fetch dev and call virNodeDeviceObjUnlock(obj) here before
  getting to out: i.e. keep the crucial actions closer to the spot and
  stay generic in the exit section.

> +                        found = 1;
> +                        goto out;
> +                    }
> +                }
> +            }
> +            cap = cap->next;
> +        }
> +
> +        virNodeDeviceObjUnlock(obj);
> +    }
> +
> +out:
> +    if (found) {
> +        dev = virGetNodeDevice(conn, obj->def->name);
> +        virNodeDeviceObjUnlock(obj);
> +    }
> +
> +    return dev;
> +}
> +
> +
>  static char *nodeDeviceDumpXML(virNodeDevicePtr dev,
>                                 unsigned int flags ATTRIBUTE_UNUSED)
>  {
> @@ -258,6 +307,310 @@ cleanup:
>  }
>  
>  
> +static int
> +nodeDeviceVportCreateDelete(virConnectPtr conn,
> +                            const int parent_host,
> +                            const char *wwpn,
> +                            const char *wwnn,
> +                            int operation)
> +{
> +    int fd = -1;
> +    int retval = 0;
> +    char *operation_path;

  I would initilize it to NULL

> +    const char *operation_file;
> +    char *vport_name;
> +    size_t towrite = 0;
> +    unsigned int written = 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:
> +        virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
> +                                 _("Invalid vport operation (%d)"), operation);
> +        retval = -1;
> +        goto no_unwind;
> +        break;
> +    }
> +
> +    if (virAsprintf(&operation_path,
> +                    "%shost%d%s",
> +                    LINUX_SYSFS_FC_HOST_PREFIX,
> +                    parent_host,
> +                    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",
> +                    wwpn,
> +                    wwnn) < 0) {
> +
> +        virReportOOMError(conn);
> +        retval = -1;
> +        goto close_fd;
> +    }
> +
> +    towrite = strlen(vport_name);
> +    written = safewrite(fd, vport_name, towrite);
> +    if (written != towrite) {
> +        virReportSystemError(conn, errno,
> +                             _("Write of '%s' to '%s' during "
> +                               "vport create/delete failed "
> +                               "(towrite: %lu written: %d)"),
> +                             vport_name, operation_path,
> +                             towrite, written);
> +        retval = -1;
> +    }
> +
> +    VIR_FREE(vport_name);
> +close_fd:
> +    close(fd);
> +free_path:
> +    VIR_FREE(operation_path);
> +no_unwind:
> +    VIR_DEBUG("%s", _("Vport operation complete"));
> +    return retval;
> +}

  and unify the 3 exit labels with
    if (fd >= 0)
        close(fd)
    VIR_FREE(operation_path);
    VIR_DEBUG(...)

if you initilize the variable on enter like fd you can have a single
exit point, simpler code, less prone to breakage if the code is modified
later

[...]
> +static int
> +get_parent_host(virConnectPtr conn,
> +                virDeviceMonitorStatePtr driver,
> +                virNodeDeviceDefPtr def,
> +                int *parent_host)
> +{
> +    virNodeDeviceObjPtr parent = NULL;
> +    virNodeDevCapsDefPtr cap = NULL;
> +    int ret = 0;
> +
> +    parent = virNodeDeviceFindByName(&driver->devs, def->parent);
> +    if (parent == NULL) {
> +        virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
> +                                 _("Could not find parent device for '%s'"),
> +                                 def->name);
> +        ret = -1;
> +        goto out;
> +    }
> +
> +    cap = parent->def->caps;
> +    while (cap != NULL) {
> +        if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
> +            *parent_host = cap->data.scsi_host.host;
> +            break;
> +        }
> +
> +        cap = cap->next;
> +    }
> +
> +    if (cap == NULL) {
> +        virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
> +                                 _("Device %s is not a SCSI host"),
> +                                 parent->def->name);
> +        ret = -1;
> +    }
> +
> +out:
> +    if (parent != NULL) {
> +        virNodeDeviceObjUnlock(parent);
> +    }

  again I would move it before the break and replace the break to a goto
  out:

I find a bit weird to have only unlocking in this function, but I assume
it's just because we get a locked parent as a result of FindByName

> +
> +    return ret;
> +}
> +
[...]
> +    while (dev == NULL && now - start < LINUX_NEW_DEVICE_WAIT_TIME) {

              better to fully parenthesize 

> +        /* We can't hold the driver lock while we wait because the
> +           wait for devices call takes it.  It's safe to drop the lock
> +           because we're done with the driver structure at this point
> +           anyway.  We take it again when we look to see what, if
> +           anything, was created. */
> +        nodeDeviceUnlock(driver);
> +        virNodeDeviceWaitForDevices(conn);
> +        nodeDeviceLock(driver);
> +
> +        dev = nodeDeviceLookupByWWN(conn, wwnn, wwpn);
> +
> +        if (dev == NULL) {
> +            sleep(5);

  Hum, we do sleep with the lock here, and for a long time !

> +            now = time(NULL);
> +            if (now == (time_t)-1) {
> +                virNodeDeviceReportError(dev->conn, VIR_ERR_INTERNAL_ERROR,
> +                                         "%s", _("Could not get current time"));
> +                break;
> +            }
> +        }
> +    }
> +
> +    return dev;
> +}
[...]
> --- a/src/node_device_conf.c
> +++ b/src/node_device_conf.c
> @@ -53,9 +53,34 @@ VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
>                "80203",
>                "80211")
>  
> +VIR_ENUM_IMPL(virNodeDevHBACap, VIR_NODE_DEV_CAP_HBA_LAST,
> +              "fc_host",
> +              "vport_ops")
>  
>  #define virNodeDeviceLog(msg...) fprintf(stderr, msg)

  errr, can we fix that while modifying this module, we really ought
to use the normal logging internal APIs
  Well there are other places:

network_driver.c:#define networkLog(level, msg...) fprintf(stderr, msg)
node_device_conf.c:#define virNodeDeviceLog(msg...) fprintf(stderr, msg)
storage_conf.c:#define virStorageLog(msg...) fprintf(stderr, msg)
storage_driver.c:#define storageLog(msg...) fprintf(stderr, msg)

  I will rather do a separate PATCH to plug those...

> +    if ((fd = open(wwnn_path, O_RDONLY)) < 0) {
> +        goto out;
> +    }
> +
> +    memset(buf, 0, sizeof(buf));
> +    if (saferead(fd, buf, sizeof(buf)) < 0) {
> +        goto out;

  here fd is open but out: doesn't close it.

> +    }
> +
> +    close(fd);

  just set back fd to -1 here and in other places where you close it
and in out: add
    if (fd >= 0)
        close(fd);


> +    if ((fd = open(wwpn_path, O_RDONLY)) < 0) {
> +        goto out;
> +    }
> +
> +    memset(buf, 0, sizeof(buf));
> +    if (saferead(fd, buf, sizeof(buf)) < 0) {
> +        goto out;

  same here. Alternatively just close(fd) before goto out; in those 2
  cases.


>  static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
>                                  union _virNodeDevCapData *d)
>  {
>      (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host);
> +    (void)check_fc_host(d);
> +    (void)check_vport_capable(d);
>      return 0;
>  }

  Hum, I find hard to justify those void casts

One thing I find missing is that we extend the capabilities but I don't
see any associated documentation, or is that already covered ?

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list