[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