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

John Ferlan jferlan at redhat.com
Mon Nov 14 22:17:45 UTC 2016



On 11/14/2016 05:06 PM, Eric Farman wrote:
> 
> 
> On 11/14/2016 04:40 PM, John Ferlan wrote:
>>
>> 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.
> 
> Mine too.  :)
> 
>>   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.
> 
> Would "SCSIHostVHost" be acceptable?  Writing "SCSIHostvHost" looks like
> a typo to me.
> 

That's fine... It's funny reading HostvHost alone gets me to thinking of
the short hand for sports matches "verses".

John

>>
>>> 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.
> 
> I'll keep an eye out.  As long as I'm mucking around in this code, if we
> can straighten some things out that would be a Good Thing.
> 
>  - Eric
> 
>>
>>>>>    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