[libvirt] [PATCH 13/25] conf: Generate address for scsi host device automatically

John Ferlan jferlan at redhat.com
Tue May 7 13:42:03 UTC 2013


On 05/03/2013 02:07 PM, Osier Yang wrote:
> With unknown good reasons, the attribute "bus" of scsi device
> address is always set to 0, same for attribute "target". (See
> virDomainDiskDefAssignAddress).
> 
> Though we might need to change the algrithom to honor "bus"

s/algrithom/algorithm

> and "target" too, it's another story. The address generator

s/it's another story/that's a different issue

> for scsi host device in this patch just follows the unknown
> good reasons, only considering the "controller" and "unit".
> It walks through all scsi controllers and their units, to see
> if the address $controller:0:0:$unit can be used, if found
> one, it sits on it, otherwise, it creates a new controller
> (actually the controller is created implicitly by someone
> else), and sits on $new_controller:0:0:0 instead.

Implicit creation
> 
> ---
> Since it needs to add the controllers for "drive" type address
> implicitly, I add the generator in domain_conf.c instead of
> the specific the driver, e.g. qemu.
> ---
>  src/conf/domain_conf.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 139 insertions(+), 5 deletions(-)
> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 31a8c46..cff2b46 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -8658,8 +8658,140 @@ error:
>      return NULL;
>  }
>  
> +/* Check if a drive type address $controller:0:0:$unit is already
> + * taken by a disk or not.
> + */
> +static bool
> +virDomainDriveAddressIsUsedByDisk(virDomainDefPtr def,
> +                                  enum virDomainDiskBus type,
> +                                  unsigned int controller,
> +                                  unsigned int unit)
> +{
> +    virDomainDiskDefPtr disk;
> +    int i;
> +
> +    for (i = 0; i < def->ndisks; i++) {
> +        disk = def->disks[i];
> +
> +        if (disk->bus != type ||
> +            disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
> +            continue;
> +
> +        if (disk->info.addr.drive.controller == controller &&
> +            disk->info.addr.drive.unit == unit &&
> +            disk->info.addr.drive.bus == 0 &&
> +            disk->info.addr.drive.target == 0)
> +            return true;
> +    }
> +
> +    return false;
> +}
> +
> +/* Check if a drive type address $controller:0:0:$unit is already
> + * taken by a host device or not.
> + */
> +static bool
> +virDomainDriveAddressIsUsedByHostdev(virDomainDefPtr def,
> +                                     enum virDomainHostdevSubsysType type,
> +                                     unsigned int controller,
> +                                     unsigned int unit)
> +{
> +    virDomainHostdevDefPtr hostdev;
> +    int i;
> +
> +    for (i = 0; i < def->nhostdevs; i++) {
> +        hostdev = def->hostdevs[i];
> +
> +        if (hostdev->source.subsys.type != type)
> +            continue;
> +
> +        if (hostdev->info->addr.drive.controller == controller &&
> +            hostdev->info->addr.drive.unit == unit &&
> +            hostdev->info->addr.drive.bus == 0 &&
> +            hostdev->info->addr.drive.target == 0)
> +            return true;
> +    }
> +
> +    return false;
> +}
> +
> +/* Find out the next usable "unit" of a specific controller */
> +static int
> +virDomainControllerSCSINextUnit(virDomainDefPtr def,
> +                                unsigned int max_unit,
> +                                unsigned int controller)
> +{
> +    int i;
> +
> +    for (i = 0; i < max_unit; i++) {
> +        /* The controller itself is on unit 7 */
> +        if (max_unit == 16 && i == 7)

I would expect 16 and 7 to be constants

The 'max_unit' check is irrelevant if max_unit=7, then we're not getting
here anyway...

> +            continue;
> +
> +        if (!virDomainDriveAddressIsUsedByDisk(def,
> +                VIR_DOMAIN_DISK_BUS_SCSI, controller, i) &&
> +            !virDomainDriveAddressIsUsedByHostdev(def,
> +                VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI, controller, i))
> +            return i;
> +    }
> +
> +    return -1;
> +}
> +
> +static int
> +virDomainHostdevAssignAddress(virDomainXMLOptionPtr xmlopt,
> +                              virDomainDefPtr def,
> +                              virDomainHostdevDefPtr hostdev)

This ends up being Scsi specific right?  E.G. AssignSCSIAddress instead
of generic AssignAddress  (or wherever the "best" place is to put SCSI)

> +{
> +    unsigned int max_unit;
> +    int next_unit;
> +    unsigned nscsi_controllers;

s/;/ = 0;

> +    bool found;
> +    int i;
> +
> +    if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> +        return -1;
> +
> +    /* See comments in virDomainDiskDefAssignAddress */
> +    if (xmlopt->config.hasWideScsiBus)
> +        max_unit = 16;
> +    else
> +        max_unit = 7;

Guess I would have figured these would be constants somewhere...  Not
that I expect the values to change...

Units are numbered 0 -> 15 and 0 -> 6 then?

> +
> +    for (i = 0; i < def->ncontrollers; i++) {
> +        if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
> +            continue;
> +
> +        nscsi_controllers++;

If we're "implicitly" creating a new controller, then is it's number
based on the total number of controllers or the next scsi controller?

> +        next_unit = virDomainControllerSCSINextUnit(def, max_unit,
> +                                                    def->controllers[i]->idx);
> +        if (next_unit >= 0) {
> +            found = true;
> +            break;
> +        }
> +    }
> +
> +    hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
> +
> +    if (found) {
> +        hostdev->info->addr.drive.controller = def->controllers[i]->idx;
> +        hostdev->info->addr.drive.bus = 0;
> +        hostdev->info->addr.drive.target = 0;
> +        hostdev->info->addr.drive.unit = next_unit;
> +    } else {
> +        hostdev->info->addr.drive.controller = nscsi_controllers + 1;

To be fair, I'm not familiar (yet) with how things are laid out, but it
would seem to me that this might not be returning what you want/expect.

I'm missing a nuance here - the 'controller' field is generally based
off the def->controllers[i]->idx value, except when we're "implicitly
creating" one.  In this case it's just a 'random' value based on some
count of existing nscsi_controllers.

If there are zero existing controllers, then we start at 1
If there is one existing/full controller, then we start at 2

How does the 'idx' value get populated?  Is it possible that this
setting conflicts with a different and non scsi controller?

Is there a max controller number we shouldn't go past?

John


> +        hostdev->info->addr.drive.bus = 0;
> +        hostdev->info->addr.drive.target = 0;
> +        hostdev->info->addr.drive.unit = 0;
> +    }
> +
> +    return 0;
> +}
> +
>  static virDomainHostdevDefPtr
> -virDomainHostdevDefParseXML(const xmlNodePtr node,
> +virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt,
> +                            virDomainDefPtr vmdef,
> +                            const xmlNodePtr node,
>                              xmlXPathContextPtr ctxt,
>                              virHashTablePtr bootHash,
>                              unsigned int flags)
> @@ -8719,7 +8851,8 @@ virDomainHostdevDefParseXML(const xmlNodePtr node,
>              }
>              break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
> -            if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
> +            if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
> +                virDomainHostdevAssignAddress(xmlopt, vmdef, def) < 0) {
>                  virReportError(VIR_ERR_XML_ERROR, "%s",
>                                 _("SCSI host devices must have address specified"));
>                  goto error;
> @@ -9128,8 +9261,8 @@ virDomainDeviceDefParse(const char *xmlStr,
>              goto error;
>      } else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
>          dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
> -        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, ctxt, NULL,
> -                                                              flags)))
> +        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(xmlopt, def, node,
> +                                                              ctxt, NULL, flags)))
>              goto error;
>      } else if (xmlStrEqual(node->name, BAD_CAST "controller")) {
>          dev->type = VIR_DOMAIN_DEVICE_CONTROLLER;
> @@ -11477,7 +11610,8 @@ virDomainDefParseXML(xmlDocPtr xml,
>      for (i = 0 ; i < n ; i++) {
>          virDomainHostdevDefPtr hostdev;
>  
> -        hostdev = virDomainHostdevDefParseXML(nodes[i], ctxt, bootHash, flags);
> +        hostdev = virDomainHostdevDefParseXML(xmlopt, def, nodes[i],
> +                                              ctxt, bootHash, flags);
>          if (!hostdev)
>              goto error;
>  
> 




More information about the libvir-list mailing list