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 ||
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;
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);
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;
/* 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);
}
/*
* 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
*
* Authors:
* Han Cheng <hanc.fnst@cn.fujitsu.com>
+ * Osier Yang <jyang@redhat.com>
*/
#include <config.h>
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;
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 *
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