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(a)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(a)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(a)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,
>>