[libvirt] [PATCH v3 04/10] util: Management routines for scsi_host devices

John Ferlan jferlan at redhat.com
Mon Nov 14 21:40:24 UTC 2016



On 11/14/2016 03:38 PM, Eric Farman wrote:
> 
> 
> On 11/11/2016 04:44 PM, John Ferlan wrote:
>> While perhaps mostly obvious - you need some sort of commit message here.
>>
>> On 11/08/2016 01:26 PM, Eric Farman wrote:
>>> Signed-off-by: Eric Farman <farman at linux.vnet.ibm.com>
>>> ---
>>>   po/POTFILES.in           |   1 +
>>>   src/Makefile.am          |   1 +
>>>   src/libvirt_private.syms |  19 +++
>>>   src/util/virhost.c       | 299
>>> +++++++++++++++++++++++++++++++++++++++++++++++
>>>   src/util/virhost.h       |  72 ++++++++++++
>>>   src/util/virhostdev.c    | 155 ++++++++++++++++++++++++
>>>   src/util/virhostdev.h    |  16 +++
>>>   tests/qemuxml2argvmock.c |   9 ++
>>>   8 files changed, 572 insertions(+)
>>>   create mode 100644 src/util/virhost.c
>>>   create mode 100644 src/util/virhost.h
>>>
>> I fear someone will equate "virhost" to host virtual functions as
>> opposed to what it is.  You'll note there's virhostcpu, virhostdev, and
>> virhostmem - each of which are utility API's for that subsystem.
>>
>> So I think this needs to become 'virscsihost.{c,h}' and of course the
>> API's are 'virSCSIHostDevice' prefixed instead of 'virHostDevice'.
>> Alternatively, the functions could go in virscsi.c, but I do prefer the
>> separation.
>>
>>> diff --git a/po/POTFILES.in b/po/POTFILES.in
>>> index 1469240..a7cc542 100644
>>> --- a/po/POTFILES.in
>>> +++ b/po/POTFILES.in
>>> @@ -199,6 +199,7 @@ src/util/virfirewall.c
>>>   src/util/virfirmware.c
>>>   src/util/virhash.c
>>>   src/util/virhook.c
>>> +src/util/virhost.c
>>>   src/util/virhostcpu.c
>>>   src/util/virhostdev.c
>>>   src/util/virhostmem.c
>>> diff --git a/src/Makefile.am b/src/Makefile.am
>>> index d417b6e..404c64e 100644
>>> --- a/src/Makefile.am
>>> +++ b/src/Makefile.am
>>> @@ -122,6 +122,7 @@ UTIL_SOURCES =                            \
>>>           util/virhash.c util/virhash.h            \
>>>           util/virhashcode.c util/virhashcode.h        \
>>>           util/virhook.c util/virhook.h            \
>>> +        util/virhost.c util/virhost.h            \
>>>           util/virhostcpu.c util/virhostcpu.h util/virhostcpupriv.h \
>>>           util/virhostdev.c util/virhostdev.h        \
>>>           util/virhostmem.c util/virhostmem.h        \
>>> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
>>> index 74dd527..ff535f9 100644
>>> --- a/src/libvirt_private.syms
>>> +++ b/src/libvirt_private.syms
>>> @@ -1675,6 +1675,23 @@ virHookInitialize;
>>>   virHookPresent;
>>>     +# util/virhost.h
>>> +virHostDeviceFileIterate;
>>> +virHostDeviceFree;
>>> +virHostDeviceGetName;
>>> +virHostDeviceListAdd;
>>> +virHostDeviceListCount;
>>> +virHostDeviceListDel;
>>> +virHostDeviceListFind;
>>> +virHostDeviceListFindIndex;
>> This one is not used externally, so it could just be static to virhost.c
>>
>>> +virHostDeviceListGet;
>>> +virHostDeviceListNew;
>>> +virHostDeviceListSteal;
>>> +virHostDeviceNew;
>>> +virHostDeviceSetUsedBy;
>>> +virHostOpenVhostSCSI;
>>> +
>>> +
>>>   # util/virhostdev.h
>>>   virHostdevFindUSBDevice;
>>>   virHostdevManagerGetDefault;
>>> @@ -1682,10 +1699,12 @@ virHostdevPCINodeDeviceDetach;
>>>   virHostdevPCINodeDeviceReAttach;
>>>   virHostdevPCINodeDeviceReset;
>>>   virHostdevPrepareDomainDevices;
>>> +virHostdevPrepareHostDevices;
> 
> As I alluded to in my response in patch 3, taking your s/Host/SCSIHost/
> comment to heart breaks down here because
> "virHostdevPrepareSCSIHostDevices" was introduced by commit 17bddc46. 


Ugh... So many close names is making my eyes hurt. I was afraid we may
end with this dilemma. Trust me I waffled a lot about saying anything on
this, but it eventually got to a point where there were virHostXXX API's
that I really had to say something.  My other thought along the way was
to use the "vHost" in some way (e.g. virSCSIHostvHost prefixes).

I was hoping though that a generic solution would work, but felt it may
not work for everything and we could address those as we went along.

For this particular one what you're adding I think would be:

   virHostdevPrepareSCSIHostvHostDevices

That would say to me as a reader that I'm modifying a scsi_host device
using the vhost protocol. Search around for "SCSIiSCSI" to see some
really ugly names.

> So now I'm torn in how far to correlate the changes.  I currently have
> two (to-be-squashed) patches that does "s/virHost/virSCSIHost/" and
> "s/HOST/SCSIHOST/" within the context of this series, but going farther
> means qemuHostdevPrepareSCSIHostDevices calls
> virHostdevPrepareHostDevices, because qemuHostdevPrepareSCSIDevices
> calls virHostdevPrepareSCSIDevices, whihc may call
> virHostdevPrepareSCSIHostDevices
> 

I recall hitting something else during review, but now I cannot remember
what it was... There was some name that should have use SCSI, but
didn't. I thought I flagged it, but I might not of. Now I cannot
remember what it was.  It was something I found while looking at the PCI
address code. <sigh> must've been interrupted and lost my train of
thought and didn't get back to it.

>>>   virHostdevPreparePCIDevices;
>>>   virHostdevPrepareSCSIDevices;
>>>   virHostdevPrepareUSBDevices;
>>>   virHostdevReAttachDomainDevices;
>>> +virHostdevReAttachHostDevices;
>>>   virHostdevReAttachPCIDevices;
>>>   virHostdevReAttachSCSIDevices;
>>>   virHostdevReAttachUSBDevices;
>>> diff --git a/src/util/virhost.c b/src/util/virhost.c
>>> new file mode 100644
>>> index 0000000..9b5f524
>>> --- /dev/null
>>> +++ b/src/util/virhost.c
>>> @@ -0,0 +1,299 @@
>>> +/*
>>> + * virhost.c: helper APIs for managing scsi_host devices
>>> + *
>>> + * Copyright (C) 2016 IBM Corporation
>>> + *
>>> + * This library is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * This library is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with this library.  If not, see
>>> + * <http://www.gnu.org/licenses/>.
>>> + *
>>> + * Authors:
>>> + *     Eric Farman <farman at linux.vnet.ibm.com>
>>> + */
>>> +
>>> +#include <config.h>
>>> +#include <fcntl.h>
>>> +
>>> +#include "virhost.h"
>>> +#include "virlog.h"
>>> +#include "viralloc.h"
>>> +#include "virerror.h"
>>> +#include "virfile.h"
>>> +#include "virstring.h"
>>> +
>>> +VIR_LOG_INIT("util.host");
>>> +
>>> +#define SYSFS_VHOST_SCSI_DEVICES "/sys/kernel/config/target/vhost/"
>>> +#define VHOST_SCSI_DEVICE "/dev/vhost-scsi"
>>> +
>>> +struct _virUsedByInfo {
>>> +    char *drvname; /* which driver */
>>> +    char *domname; /* which domain */
>>> +};
>>> +typedef struct _virUsedByInfo *virUsedByInfoPtr;
>> Hmm... seeing this makes me think the code should go in virscsi.c...
>> That would seem to then allow more code reuse...
>>
>> However, looking at your virHostdevPrepareHostDevices changes for how
>> this is implemented, I see no sharing allowed/going on. Thus, there's no
>> need for a list of used_by - rather it's just a single 'used_by_drvname'
>> and 'used_by_domname' in the virSCSIHostDevice structure (similar to PCI
>> and USB).
>>
>> Unless of course you think you want to add sharing....  which I cannot
>> imagine is a good idea...
> 
> No, this is a fine idea.  I cannot see a point in permitting this.
> 
>>
>>> +
>>> +struct _virHostDevice {
>> s/Host/SCSIHost/
>>
>>> +    char *name; /* naa.<wwn> */
>>> +    char *path;
>>> +    virUsedByInfoPtr *used_by; /* driver:domain(s) using this dev */
>>> +    size_t n_used_by; /* how many domains are using this dev */
>> Looks like the above 2 get replaced by
>>
>>      char *used_by_drvname;
>>      char *used_by_domname;
>>
>> Also - looking at QEMU and "forward" thinking - there are options on the
>> qemu command line for things like boot_tpgt, num_queues, max_sectors,
>> cmd_per_lun, and bootindex... I can see the last one being asked for -
>> as in can we pass one of these to the guest to allow booting from a
>> specific LUN on the array...
>>
>>> +};
>>> +
>>> +struct _virHostDeviceList {
>> s/Host/SCSIHost/
>>
>>> +    virObjectLockable parent;
>>> +    size_t count;
>>> +    virHostDevicePtr *devs;
>>> +};
>>> +
>>> +static virClassPtr virHostDeviceListClass;
>> s/Host/SCSIHost/
>>
>> (ad nauseum ;-))
>>
>>> +
>>> +static void
>>> +virHostDeviceListDispose(void *obj)
>>> +{
>>> +    virHostDeviceListPtr list = obj;
>>> +    size_t i;
>>> +
>>> +    for (i = 0; i < list->count; i++)
>>> +        virHostDeviceFree(list->devs[i]);
>>> +
>>> +    VIR_FREE(list->devs);
>>> +}
>>> +
>>> +
>> You start w/ the newer convention of 2 spaces between functions, but it
>> ends here. After this there's always just 1 space between functions -
>> let's try to go w/ 2.
> 
> OK.
> 
>>
>>> +static int
>>> +virHostOnceInit(void)
>>> +{
>>> +    if (!(virHostDeviceListClass =
>>> virClassNew(virClassForObjectLockable(),
>>> +                                               "virHostDeviceList",
>>> +                                              
>>> sizeof(virHostDeviceList),
>>> +                                              
>>> virHostDeviceListDispose)))
>>> +        return -1;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +VIR_ONCE_GLOBAL_INIT(virHost)
>>> +
>>> +/* For virReportOOMError()  and virReportSystemError() */
>>> +#define VIR_FROM_THIS VIR_FROM_NONE
>>> +
>>> +int
>>> +virHostOpenVhostSCSI(int *vhostfd)
>>> +{
>>> +    if (!virFileExists(VHOST_SCSI_DEVICE))
>>> +        goto error;
>>> +
>>> +    *vhostfd = open(VHOST_SCSI_DEVICE, O_RDWR);
>>> +
>>> +    if (*vhostfd < 0) {
>>> +        virReportSystemError(errno, _("Failed to open %s"),
>>> VHOST_SCSI_DEVICE);
>>> +        goto error;
>>> +    }
>>> +
>>> +    return 0;
>>> +
>>> + error:
>>> +    VIR_FORCE_CLOSE(*vhostfd);
>>> +
>>> +    return -1;
>>> +}
>>> +
>>> +static void
>>> +virHostDeviceUsedByInfoFree(virUsedByInfoPtr used_by)
>>> +{
>> I think this ends up going away since things aren't shareable.
>>
>>> +    VIR_FREE(used_by->drvname);
>>> +    VIR_FREE(used_by->domname);
>>> +    VIR_FREE(used_by);
>>> +}
>>> +
>>> +void
>>> +virHostDeviceListDel(virHostDeviceListPtr list,
>>> +                     virHostDevicePtr dev,
>>> +                     const char *drvname,
>>> +                     const char *domname)
>>> +{
>>> +    virHostDevicePtr tmp = NULL;
>>> +    size_t i;
>>> +
>> This will need to be adjusted since (I assume) you don't want shareable
>> scsi_host devices
>>
>>> +    for (i = 0; i < dev->n_used_by; i++) {
>>> +        if (STREQ_NULLABLE(dev->used_by[i]->drvname, drvname) &&
>>> +            STREQ_NULLABLE(dev->used_by[i]->domname, domname)) {
>>> +            if (dev->n_used_by > 1) {
>>> +                virHostDeviceUsedByInfoFree(dev->used_by[i]);
>>> +                VIR_DELETE_ELEMENT(dev->used_by, i, dev->n_used_by);
>>> +            } else {
>>> +                tmp = virHostDeviceListSteal(list, dev);
>>> +                virHostDeviceFree(tmp);
>>> +            }
>>> +            break;
>>> +        }
>>> +    }
>>> +}
>>> +
>>> +int
>> s/int/static int/
>>
>>> +virHostDeviceListFindIndex(virHostDeviceListPtr list,
>>> virHostDevicePtr dev)
>>> +{
>>> +    size_t i;
>>> +
>>> +    for (i = 0; i < list->count; i++) {
>>> +        virHostDevicePtr other = list->devs[i];
>>> +        if (STREQ_NULLABLE(other->name, dev->name))
>>> +            return i;
>>> +    }
>>> +    return -1;
>>> +}
>>> +
>>> +virHostDevicePtr
>>> +virHostDeviceListGet(virHostDeviceListPtr list, int idx)
>>> +{
>>> +    if (idx >= list->count || idx < 0)
>>> +        return NULL;
>>> +
>>> +    return list->devs[idx];
>>> +}
>>> +
>>> +size_t
>>> +virHostDeviceListCount(virHostDeviceListPtr list)
>>> +{
>>> +    return list->count;
>>> +}
>>> +
>>> +virHostDevicePtr
>>> +virHostDeviceListSteal(virHostDeviceListPtr list,
>>> +                       virHostDevicePtr dev)
>>> +{
>>> +    virHostDevicePtr ret = NULL;
>>> +    size_t i;
>>> +
>>> +    for (i = 0; i < list->count; i++) {
>>> +        if (STREQ_NULLABLE(list->devs[i]->name, dev->name)) {
>>> +            ret = list->devs[i];
>>> +            VIR_DELETE_ELEMENT(list->devs, i, list->count);
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +virHostDevicePtr
>>> +virHostDeviceListFind(virHostDeviceListPtr list, virHostDevicePtr dev)
>>> +{
>>> +    int idx;
>>> +
>>> +    if ((idx = virHostDeviceListFindIndex(list, dev)) >= 0)
>>> +        return list->devs[idx];
>>> +    else
>>> +        return NULL;
>>> +}
>>> +
>>> +int
>>> +virHostDeviceListAdd(virHostDeviceListPtr list,
>>> +                     virHostDevicePtr dev)
>>> +{
>>> +    if (virHostDeviceListFind(list, dev)) {
>>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>>> +                       _("Device %s is already in use"), dev->name);
>>> +        return -1;
>>> +    }
>>> +    return VIR_APPEND_ELEMENT(list->devs, list->count, dev);
>>> +}
>>> +
>>> +virHostDeviceListPtr
>>> +virHostDeviceListNew(void)
>>> +{
>>> +    virHostDeviceListPtr list;
>>> +
>>> +    if (virHostInitialize() < 0)
>>> +        return NULL;
>>> +
>>> +    if (!(list = virObjectLockableNew(virHostDeviceListClass)))
>>> +        return NULL;
>>> +
>>> +    return list;
>> or simply return virObjectLockableNew(virSCSIHostDeviceListClass); and
>> then 'list' is not needed.
>>
>>> +}
>>> +
>>> +int
>>> +virHostDeviceSetUsedBy(virHostDevicePtr dev,
>>> +                       const char *drvname,
>>> +                       const char *domname)
>>> +{
>> Without sharing, this mimics PCI/USB instead...
>>
>>> +    virUsedByInfoPtr copy;
>>> +    if (VIR_ALLOC(copy) < 0)
>>> +        return -1;
>>> +    if (VIR_STRDUP(copy->drvname, drvname) < 0 ||
>>> +        VIR_STRDUP(copy->domname, domname) < 0)
>>> +        goto cleanup;
>>> +
>>> +    if (VIR_APPEND_ELEMENT(dev->used_by, dev->n_used_by, copy) < 0)
>>> +        goto cleanup;
>>> +
>>> +    return 0;
>>> +
>>> + cleanup:
>>> +    virHostDeviceUsedByInfoFree(copy);
>>> +    return -1;
>>> +}
>>> +
>>> +int
>>> +virHostDeviceFileIterate(virHostDevicePtr dev,
>>> +                         virHostDeviceFileActor actor,
>>> +                         void *opaque)
>>> +{
>>> +    return (actor)(dev, dev->path, opaque);
>>> +}
>>> +
>>> +const char *
>>> +virHostDeviceGetName(virHostDevicePtr dev)
>>> +{
>>> +    return dev->name;
>>> +}
>>> +
>>> +virHostDevicePtr
>>> +virHostDeviceNew(const char *name)
>>> +{
>>> +    virHostDevicePtr dev;
>>> +
>>> +    if (VIR_ALLOC(dev) < 0)
>>> +        return NULL;
>>> +
>>> +    if (VIR_STRDUP(dev->name, name) < 0) {
>>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>>> +                       _("dev->name buffer overflow: %s"),
>>> +                       name);
>>> +        goto error;
>>> +    }
>>> +
>>> +    if (virAsprintf(&dev->path, "%s/%s",
>>> +                    SYSFS_VHOST_SCSI_DEVICES, name) < 0)
>>> +        goto cleanup;
>>> +
>>> +    VIR_DEBUG("%s: initialized", dev->name);
>>> +
>>> + cleanup:
>>> +    return dev;
>>> +
>>> + error:
>>> +    virHostDeviceFree(dev);
>>> +    dev = NULL;
>>> +    goto cleanup;
>>> +}
>>> +
>>> +void
>>> +virHostDeviceFree(virHostDevicePtr dev)
>>> +{
>>      size_t i;
>>
>>> +    if (!dev)
>>> +        return;
>>> +    VIR_DEBUG("%s: freeing", dev->name);
>> Would be nice if it was freeing everything in 'dev' before freeing dev...
> 
> Oops!
> 
>>
>> Thus you have:
>>
>>      VIR_FREE(dev->name);
>>      VIR_FREE(dev->path);
>>      VIR_FREE(dev->used_by_drvname);
>>      VIR_FREE(dev->used_by_domname);
>>
>>> +    VIR_FREE(dev);
>>> +}
>>> diff --git a/src/util/virhost.h b/src/util/virhost.h
>>> new file mode 100644
>>> index 0000000..6d7b790
>>> --- /dev/null
>>> +++ b/src/util/virhost.h
>>> @@ -0,0 +1,72 @@
>>> +/*
>>> + * virhost.h: helper APIs for managing host scsi_host devices
>>> + *
>>> + * Copyright (C) 2016 IBM Corporation
>>> + *
>>> + * This library is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * This library is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with this library.  If not, see
>>> + * <http://www.gnu.org/licenses/>.
>>> + *
>>> + * Authors:
>>> + *     Eric Farman <farman at linux.vnet.ibm.com>
>>> + */
>>> +
>>> +#ifndef __VIR_HOST_H__
>>> +# define __VIR_HOST_H__
>>> +
>>> +# include "internal.h"
>>> +# include "virobject.h"
>>> +# include "virutil.h"
>>> +
>>> +typedef struct _virHostDevice virHostDevice;
>>> +typedef virHostDevice *virHostDevicePtr;
>>> +typedef struct _virHostDeviceAddress virHostDeviceAddress;
>>> +typedef virHostDeviceAddress *virHostDeviceAddressPtr;
>>> +typedef struct _virHostDeviceList virHostDeviceList;
>>> +typedef virHostDeviceList *virHostDeviceListPtr;
>>> +
>>> +struct _virHostDeviceAddress {
>>> +    char *wwpn;
>>> +};
>> Hmmm.. this would seemingly duplicate name without the "naa.", but in
>> the long run it's not even used - so why is it necessary?
>>
>> Then again as it turns out a "vhost-scsi-pci" or "vhost-scsi-ccw" device
>> object is created. Each of those would seemingly need a controller to
>> use wouldn't they?
> 
> Are you referring to a <controller> tag?  Or something else?
> 

Um.. oh yeah. I think at this point it wasn't totally clear what address
was going to be used in the guest.  This is probably where I started
down the rabbit hole of figuring out how PCI addresses would be added to
the XML.

>>   So the address would seem to be important, but is not
>> handled.
> 
> Will check how the PCI handling is broken.  Seemed okay for CCW, but
> maybe I've missed something there too.
> 

I think you're letting QEMU pick which may not be a good idea based on
our recent experience.

John
>  - Eric
> 
>>
>>> +
>>> +typedef int (*virHostDeviceFileActor)(virHostDevicePtr dev,
>>> +                                      const char *name, void *opaque);
>>> +
>>> +int virHostDeviceFileIterate(virHostDevicePtr dev,
>>> +                             virHostDeviceFileActor actor,
>>> +                             void *opaque);
>>> +const char *virHostDeviceGetName(virHostDevicePtr dev);
>>> +virHostDevicePtr virHostDeviceListGet(virHostDeviceListPtr list,
>>> +                                      int idx);
>>> +size_t virHostDeviceListCount(virHostDeviceListPtr list);
>>> +virHostDevicePtr virHostDeviceListSteal(virHostDeviceListPtr list,
>>> +                                        virHostDevicePtr dev);
>>> +int virHostDeviceListFindIndex(virHostDeviceListPtr list,
>>> +                               virHostDevicePtr dev);
>> Remove the def since it's local to virhost.c
>>
>>> +virHostDevicePtr virHostDeviceListFind(virHostDeviceListPtr list,
>>> +                                       virHostDevicePtr dev);
>>> +int  virHostDeviceListAdd(virHostDeviceListPtr list,
>>> +                          virHostDevicePtr dev);
>>> +void virHostDeviceListDel(virHostDeviceListPtr list,
>>> +                          virHostDevicePtr dev,
>>> +                          const char *drvname,
>>> +                          const char *domname);
>>> +virHostDeviceListPtr virHostDeviceListNew(void);
>>> +virHostDevicePtr virHostDeviceNew(const char *name);
>>> +int virHostDeviceSetUsedBy(virHostDevicePtr dev,
>>> +                           const char *drvname,
>>> +                           const char *domname);
>>> +void virHostDeviceFree(virHostDevicePtr dev);
>>> +int virHostOpenVhostSCSI(int *vhostfd);
>>> +
>>> +#endif /* __VIR_HOST_H__ */
>>> diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
>>> index 9c2262e..b92e246 100644
>>> --- a/src/util/virhostdev.c
>>> +++ b/src/util/virhostdev.c
>>> @@ -146,6 +146,7 @@ virHostdevManagerDispose(void *obj)
>>>       virObjectUnref(hostdevMgr->inactivePCIHostdevs);
>>>       virObjectUnref(hostdevMgr->activeUSBHostdevs);
>>>       virObjectUnref(hostdevMgr->activeSCSIHostdevs);
>>> +    virObjectUnref(hostdevMgr->activeHostHostdevs);
>>>       VIR_FREE(hostdevMgr->stateDir);
>>>   }
>>>   @@ -170,6 +171,9 @@ virHostdevManagerNew(void)
>>>       if (!(hostdevMgr->activeSCSIHostdevs = virSCSIDeviceListNew()))
>>>           goto error;
>>>   +    if (!(hostdevMgr->activeHostHostdevs = virHostDeviceListNew()))
>>> +        goto error;
>>> +
>>>       if (privileged) {
>>>           if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0)
>>>               goto error;
>>> @@ -1472,6 +1476,102 @@
>>> virHostdevPrepareSCSIDevices(virHostdevManagerPtr mgr,
>>>       return -1;
>>>   }
>>>   +int
>>> +virHostdevPrepareHostDevices(virHostdevManagerPtr mgr,
>>> +                             const char *drv_name,
>>> +                             const char *dom_name,
>>> +                             virDomainHostdevDefPtr *hostdevs,
>>> +                             int nhostdevs)
>>> +{
>>> +    size_t i, j;
>>> +    int count;
>>> +    virHostDeviceListPtr list;
>>> +    virHostDevicePtr tmp;
>>> +
>>> +    if (!nhostdevs)
>>> +        return 0;
>>> +
>>> +    /* To prevent situation where scsi_host device is assigned to
>>> two domains
>>> +     * we need to keep a list of currently assigned scsi_host devices.
>>> +     * This is done in several loops which cannot be joined into one
>>> big
>>> +     * loop. See virHostdevPreparePCIDevices()
>>> +     */
>>> +    if (!(list = virHostDeviceListNew()))
>>> +        goto cleanup;
>>> +
>>> +    /* Loop 1: build temporary list */
>>> +    for (i = 0; i < nhostdevs; i++) {
>>> +        virDomainHostdevDefPtr hostdev = hostdevs[i];
>>> +        virDomainHostdevSubsysHostPtr hostsrc =
>>> &hostdev->source.subsys.u.host;
>>> +
>>> +        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
>>> +            hostdev->source.subsys.type !=
>>> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST)
>>> +            continue;
>>> +
>>> +        if (hostsrc->protocol !=
>>> VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST) {
>>> +            continue;  /* Not supported */
>>> +        } else {
>> The else would be unnecessary - just move the virSCSIHostDevicePtr up to
>> the beginning of the for loop.
>>
>>> +            virHostDevicePtr host;
>>> +            if (!(host = virHostDeviceNew(hostsrc->wwpn)))
>>> +                goto cleanup;
>>> +
>>> +            if (virHostDeviceListAdd(list, host) < 0) {
>>> +                virHostDeviceFree(host);
>>> +                goto cleanup;
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    /* Loop 2: Mark devices in temporary list as used by @name
>>> +     * and add them to driver list. However, if something goes
>>> +     * wrong, perform rollback.
>>> +     */
>>> +    virObjectLock(mgr->activeHostHostdevs);
>>> +    count = virHostDeviceListCount(list);
>>> +
>>> +    for (i = 0; i < count; i++) {
>>> +        virHostDevicePtr host = virHostDeviceListGet(list, i);
>> See this code doesn't do any sort of sharing - so no need for a list,
>> just a single entry...
>>
>>> +        if ((tmp = virHostDeviceListFind(mgr->activeHostHostdevs,
>>> host))) {
>>> +            virReportError(VIR_ERR_OPERATION_INVALID,
>>> +                           _("SCSI_host device %s is already in use
>>> by "
>>> +                             "another domain"),
>>> +                           virHostDeviceGetName(tmp));
>>> +            goto error;
>>> +        } else {
>>> +            if (virHostDeviceSetUsedBy(host, drv_name, dom_name) < 0)
>>> +                goto error;
>>> +
>>> +            VIR_DEBUG("Adding %s to activeHostHostdevs",
>>> virHostDeviceGetName(host));
>>> +
>>> +            if (virHostDeviceListAdd(mgr->activeHostHostdevs, host)
>>> < 0)
>>> +                goto error;
>>> +        }
>>> +    }
>>> +
>>> +    virObjectUnlock(mgr->activeHostHostdevs);
>>> +
>>> +    /* Loop 3: Temporary list was successfully merged with
>>> +     * driver list, so steal all items to avoid freeing them
>>> +     * when freeing temporary list.
>>> +     */
>>> +    while (virHostDeviceListCount(list) > 0) {
>>> +        tmp = virHostDeviceListGet(list, 0);
>>> +        virHostDeviceListSteal(list, tmp);
>>> +    }
>>> +
>>> +    virObjectUnref(list);
>>> +    return 0;
>>> + error:
>>> +    for (j = 0; j < i; j++) {
>>> +        tmp = virHostDeviceListGet(list, i);
>>> +        virHostDeviceListSteal(mgr->activeHostHostdevs, tmp);
>>> +    }
>>> +    virObjectUnlock(mgr->activeHostHostdevs);
>>> + cleanup:
>>> +    virObjectUnref(list);
>>> +    return -1;
>>> +}
>>> +
>>>   void
>>>   virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
>>>                                const char *drv_name,
>>> @@ -1604,6 +1704,61 @@
>>> virHostdevReAttachSCSIDevices(virHostdevManagerPtr mgr,
>>>       virObjectUnlock(mgr->activeSCSIHostdevs);
>>>   }
>>>   +void
>>> +virHostdevReAttachHostDevices(virHostdevManagerPtr mgr,
>>> +                              const char *drv_name,
>>> +                              const char *dom_name,
>>> +                              virDomainHostdevDefPtr *hostdevs,
>>> +                              int nhostdevs)
>>> +{
>>> +    size_t i;
>>> +    virHostDevicePtr host, tmp;
>>> +
>>> +
>>> +    if (!nhostdevs)
>>> +        return;
>>> +
>>> +    virObjectLock(mgr->activeHostHostdevs);
>>> +    for (i = 0; i < nhostdevs; i++) {
>>> +        virDomainHostdevDefPtr hostdev = hostdevs[i];
>>> +        virDomainHostdevSubsysHostPtr hostsrc =
>>> &hostdev->source.subsys.u.host;
>>> +
>>> +        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
>>> +            hostdev->source.subsys.type !=
>>> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST)
>>> +            continue;
>>> +
>>> +        if (hostsrc->protocol !=
>>> VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST)
>>> +            continue; /* Not supported */
>>> +
>>> +        if (!(host = virHostDeviceNew(hostsrc->wwpn))) {
>>> +            VIR_WARN("Unable to reattach SCSI_host device %s on
>>> domain %s",
>>> +                     hostsrc->wwpn, dom_name);
>>> +            virObjectUnlock(mgr->activeHostHostdevs);
>>> +            return;
>>> +        }
>>> +
>> I assume the following changes to match PCI/USB more closely since no
>> sharing is allowed.
>>
>>> +        /* Only delete the devices which are marked as being used by
>>> @name,
>>> +         * because qemuProcessStart could fail half way through. */
>>> +
>>> +        if (!(tmp = virHostDeviceListFind(mgr->activeHostHostdevs,
>>> host))) {
>>> +            VIR_WARN("Unable to find device %s "
>>> +                     "in list of active SCSI_host devices",
>>> +                     hostsrc->wwpn);
>>> +            virHostDeviceFree(host);
>>> +            virObjectUnlock(mgr->activeHostHostdevs);
>>> +            return;
>>> +        }
>>> +
>>> +        VIR_DEBUG("Removing %s dom=%s from activeHostHostdevs",
>>> +                   hostsrc->wwpn, dom_name);
>>> +
>>> +        virHostDeviceListDel(mgr->activeHostHostdevs, tmp,
>>> +                             drv_name, dom_name);
>>> +        virHostDeviceFree(host);
>>> +    }
>>> +    virObjectUnlock(mgr->activeHostHostdevs);
>>> +}
>>> +
>>>   int
>>>   virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
>>>                                 virPCIDevicePtr pci)
>>> diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h
>>> index f2f51bd..19cef7e 100644
>>> --- a/src/util/virhostdev.h
>>> +++ b/src/util/virhostdev.h
>>> @@ -30,6 +30,7 @@
>>>   # include "virpci.h"
>>>   # include "virusb.h"
>>>   # include "virscsi.h"
>>> +# include "virhost.h"
>>>   # include "domain_conf.h"
>>>     typedef enum {
>>> @@ -53,6 +54,7 @@ struct _virHostdevManager {
>>>       virPCIDeviceListPtr inactivePCIHostdevs;
>>>       virUSBDeviceListPtr activeUSBHostdevs;
>>>       virSCSIDeviceListPtr activeSCSIHostdevs;
>>> +    virHostDeviceListPtr activeHostHostdevs;
>> s/activeHostHostdevs/activeSCSIHostHostdevs/
>>
>> John
>>
>>>   };
>>>     virHostdevManagerPtr virHostdevManagerGetDefault(void);
>>> @@ -87,6 +89,13 @@ virHostdevPrepareSCSIDevices(virHostdevManagerPtr
>>> hostdev_mgr,
>>>                                virDomainHostdevDefPtr *hostdevs,
>>>                                int nhostdevs)
>>>       ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
>>> +int
>>> +virHostdevPrepareHostDevices(virHostdevManagerPtr hostdev_mgr,
>>> +                             const char *drv_name,
>>> +                             const char *dom_name,
>>> +                             virDomainHostdevDefPtr *hostdevs,
>>> +                             int nhostdevs)
>>> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
>>>   void
>>>   virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>>>                                const char *drv_name,
>>> @@ -109,6 +118,13 @@
>>> virHostdevReAttachSCSIDevices(virHostdevManagerPtr hostdev_mgr,
>>>                                 virDomainHostdevDefPtr *hostdevs,
>>>                                 int nhostdevs)
>>>       ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
>>> +void
>>> +virHostdevReAttachHostDevices(virHostdevManagerPtr hostdev_mgr,
>>> +                              const char *drv_name,
>>> +                              const char *dom_name,
>>> +                              virDomainHostdevDefPtr *hostdevs,
>>> +                              int nhostdevs)
>>> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
>>>   int
>>>   virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
>>>                                    virDomainHostdevDefPtr *hostdevs,
>>> diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c
>>> index 78a224b..2c85140 100644
>>> --- a/tests/qemuxml2argvmock.c
>>> +++ b/tests/qemuxml2argvmock.c
>>> @@ -24,6 +24,7 @@
>>>   #include "viralloc.h"
>>>   #include "vircommand.h"
>>>   #include "vircrypto.h"
>>> +#include "virhost.h"
>>>   #include "virmock.h"
>>>   #include "virnetdev.h"
>>>   #include "virnetdevip.h"
>>> @@ -107,6 +108,14 @@ virSCSIDeviceGetSgName(const char *sysfs_prefix
>>> ATTRIBUTE_UNUSED,
>>>   }
>>>     int
>>> +virHostOpenVhostSCSI(int *vhostfd)
>>> +{
>>> +    *vhostfd = STDERR_FILENO + 1;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +int
>>>   virNetDevTapCreate(char **ifname,
>>>                      const char *tunpath ATTRIBUTE_UNUSED,
>>>                      int *tapfd,
>>>
> 




More information about the libvir-list mailing list