diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index ff50214123deae18a806578e34ba60ba82bc4f7a..fd02864d6374de7cf4c7099fc44526e0fe620dea 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2798,6 +2798,11 @@ between domains (assuming the hypervisor and OS support this). Only supported by SCSI host device. Since 1.0.6 +

+ Note: Although shareable was introduced + in 1.0.6, it did not work as + as expected until 1.2.2. +

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 45f31171cc40484db9902bf80434d84d3b760dda..f890c6ecee9a9d022647500370581d7879b7e12e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1687,7 +1687,7 @@ virSCSIDeviceGetSgName; virSCSIDeviceGetShareable; virSCSIDeviceGetTarget; virSCSIDeviceGetUnit; -virSCSIDeviceGetUsedBy; +virSCSIDeviceIsAvailable; virSCSIDeviceListAdd; virSCSIDeviceListCount; virSCSIDeviceListDel; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 86a463a65c69f592e257176ca522b596c1e4b382..2b9d274279e3722f0202e106654c34044d9674a3 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -250,13 +250,14 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, virDomainHostdevDefPtr hostdev = NULL; size_t i; int ret = -1; + virSCSIDevicePtr scsi = NULL; + virSCSIDevicePtr tmp = NULL; if (!def->nhostdevs) return 0; virObjectLock(driver->activeScsiHostdevs); for (i = 0; i < def->nhostdevs; i++) { - virSCSIDevicePtr scsi = NULL; hostdev = def->hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || @@ -271,11 +272,18 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, hostdev->shareable))) goto cleanup; - virSCSIDeviceSetUsedBy(scsi, def->name); - - if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) { + if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { + if (virSCSIDeviceSetUsedBy(tmp, def->name) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } virSCSIDeviceFree(scsi); - goto cleanup; + } else { + if (virSCSIDeviceSetUsedBy(scsi, def->name) < 0 || + virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } } } ret = 0; @@ -1118,24 +1126,29 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, for (i = 0; i < count; i++) { virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { - const char *other_name = virSCSIDeviceGetUsedBy(tmp); + bool scsi_shareable = virSCSIDeviceGetShareable(scsi); + bool tmp_shareable = virSCSIDeviceGetShareable(tmp); - if (other_name) - virReportError(VIR_ERR_OPERATION_INVALID, - _("SCSI device %s is in use by domain %s"), - virSCSIDeviceGetName(tmp), other_name); - else + if (!(scsi_shareable && tmp_shareable)) { virReportError(VIR_ERR_OPERATION_INVALID, - _("SCSI device %s is already in use"), + _("SCSI device %s is already in use by " + "other domain(s) as '%s'"), + tmp_shareable ? "shareable" : "non-shareable", virSCSIDeviceGetName(tmp)); - goto error; - } + goto error; + } - virSCSIDeviceSetUsedBy(scsi, name); - VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); + if (virSCSIDeviceSetUsedBy(tmp, name) < 0) + goto error; + } else { + if (virSCSIDeviceSetUsedBy(scsi, name) < 0) + goto error; - if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) - goto error; + VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); + + if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) + goto error; + } } virObjectUnlock(driver->activeScsiHostdevs); @@ -1380,8 +1393,8 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, virObjectLock(driver->activeScsiHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; - virSCSIDevicePtr scsi, tmp; - const char *used_by = NULL; + virSCSIDevicePtr scsi; + virSCSIDevicePtr tmp; virDomainDeviceDef dev; dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; @@ -1411,30 +1424,26 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, /* Only delete the devices which are marked as being used by @name, * because qemuProcessStart could fail on the half way. */ - tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi); - virSCSIDeviceFree(scsi); - - if (!tmp) { + if (!(tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { VIR_WARN("Unable to find device %s:%d:%d:%d " "in list of active SCSI devices", hostdev->source.subsys.u.scsi.adapter, hostdev->source.subsys.u.scsi.bus, hostdev->source.subsys.u.scsi.target, hostdev->source.subsys.u.scsi.unit); + virSCSIDeviceFree(scsi); continue; } - used_by = virSCSIDeviceGetUsedBy(tmp); - if (STREQ_NULLABLE(used_by, name)) { - VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs", - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit, - name); + VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + name); - virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp); - } + virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp, name); + virSCSIDeviceFree(scsi); } virObjectUnlock(driver->activeScsiHostdevs); } diff --git a/src/util/virscsi.c b/src/util/virscsi.c index 58d9e259a483248c3af671c8e14d331ab51ae477..9aa7f350492f0d5da182ebc9aa0967977e20c09c 100644 --- a/src/util/virscsi.c +++ b/src/util/virscsi.c @@ -1,6 +1,7 @@ /* * virscsi.c: helper APIs for managing host SCSI devices * + * Copyright (C) 2013-2014 Red Hat, Inc. * Copyright (C) 2013 Fujitsu, Inc. * * This library is free software; you can redistribute it and/or @@ -19,6 +20,7 @@ * * Authors: * Han Cheng + * Osier Yang */ #include @@ -55,7 +57,8 @@ struct _virSCSIDevice { char *name; /* adapter:bus:target:unit */ char *id; /* model:vendor */ char *sg_path; /* e.g. /dev/sg2 */ - const char *used_by; /* name of the domain using this dev */ + char **used_by; /* name of the domains using this dev */ + size_t n_used_by; /* how many domains are using this dev */ bool readonly; bool shareable; @@ -256,26 +259,36 @@ cleanup: void virSCSIDeviceFree(virSCSIDevicePtr dev) { + size_t i; + if (!dev) return; VIR_FREE(dev->id); VIR_FREE(dev->name); VIR_FREE(dev->sg_path); + for (i = 0; i < dev->n_used_by; i++) + VIR_FREE(dev->used_by[i]); + VIR_FREE(dev->used_by); VIR_FREE(dev); } -void +int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name) { - dev->used_by = name; + char *copy = NULL; + + if (VIR_STRDUP(copy, name) < 0) + return -1; + + return VIR_APPEND_ELEMENT(dev->used_by, dev->n_used_by, copy); } -const char * -virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev) +bool +virSCSIDeviceIsAvailable(virSCSIDevicePtr dev) { - return dev->used_by; + return dev->n_used_by == 0; } const char * @@ -406,10 +419,23 @@ virSCSIDeviceListSteal(virSCSIDeviceListPtr list, void virSCSIDeviceListDel(virSCSIDeviceListPtr list, - virSCSIDevicePtr dev) + virSCSIDevicePtr dev, + const char *name) { - virSCSIDevicePtr ret = virSCSIDeviceListSteal(list, dev); - virSCSIDeviceFree(ret); + virSCSIDevicePtr tmp = NULL; + size_t i; + + for (i = 0; i < dev->n_used_by; i++) { + if (STREQ_NULLABLE(dev->used_by[i], name)) { + if (dev->n_used_by > 1) { + VIR_DELETE_ELEMENT(dev->used_by, i, dev->n_used_by); + } else { + tmp = virSCSIDeviceListSteal(list, dev); + virSCSIDeviceFree(tmp); + } + break; + } + } } virSCSIDevicePtr diff --git a/src/util/virscsi.h b/src/util/virscsi.h index b2e98cac6857deaaee9a6868d2ddcc7be87cd469..aff7e5a3925c110fc75eac6df4a1918a8b060fd1 100644 --- a/src/util/virscsi.h +++ b/src/util/virscsi.h @@ -50,8 +50,8 @@ virSCSIDevicePtr virSCSIDeviceNew(const char *adapter, bool shareable); void virSCSIDeviceFree(virSCSIDevicePtr dev); -void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name); -const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev); +int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name); +bool virSCSIDeviceIsAvailable(virSCSIDevicePtr dev); const char *virSCSIDeviceGetName(virSCSIDevicePtr dev); unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev); unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev); @@ -83,7 +83,8 @@ size_t virSCSIDeviceListCount(virSCSIDeviceListPtr list); virSCSIDevicePtr virSCSIDeviceListSteal(virSCSIDeviceListPtr list, virSCSIDevicePtr dev); void virSCSIDeviceListDel(virSCSIDeviceListPtr list, - virSCSIDevicePtr dev); + virSCSIDevicePtr dev, + const char *name); virSCSIDevicePtr virSCSIDeviceListFind(virSCSIDeviceListPtr list, virSCSIDevicePtr dev);