[libvirt] [PATCH v2 07/10] qemu: Basic management functions for scsi hostdev
Osier Yang
jyang at redhat.com
Wed Apr 3 09:43:10 UTC 2013
On 01/04/13 20:00, Han Cheng wrote:
> Although virtio-scsi support SCSI PR, the device in host may do not
> support this. To avoid losing data, we only allow one scsi hostdev be
> passthrough to one guest.
>
> Signed-off-by: Han Cheng <hanc.fnst at cn.fujitsu.com>
> ---
> src/qemu/qemu_conf.h | 2 +
> src/qemu/qemu_driver.c | 3 +
> src/qemu/qemu_hostdev.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_hostdev.h | 10 ++
> src/qemu/qemu_process.c | 3 +
> 5 files changed, 245 insertions(+), 0 deletions(-)
>
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index c5ddaad..28d9685 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -37,6 +37,7 @@
> # include "vircgroup.h"
> # include "virpci.h"
> # include "virusb.h"
> +# include "virscsi.h"
> # include "cpu_conf.h"
> # include "driver.h"
> # include "virportallocator.h"
> @@ -206,6 +207,7 @@ struct _virQEMUDriver {
> virPCIDeviceListPtr activePciHostdevs;
> virPCIDeviceListPtr inactivePciHostdevs;
> virUSBDeviceListPtr activeUsbHostdevs;
> + virSCSIDeviceListPtr activeScsiHostdevs;
We have to have a share module to manage these list, Chunyan Liu is
doing it.
But it doesn't affect this patch, unless there is conflicts.
>
> /* Immutable pointer. Unsafe APIs. XXX */
> virHashTablePtr sharedDisks;
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 96bf235..408a2cb 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -682,6 +682,9 @@ qemuStartup(bool privileged,
> if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
> goto error;
>
> + if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL)
> + goto error;
> +
> if (!(qemu_driver->sharedDisks = virHashCreate(30, qemuSharedDiskEntryFree)))
> goto error;
>
> diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
> index bac38b5..96b3e8f 100644
> --- a/src/qemu/qemu_hostdev.c
> +++ b/src/qemu/qemu_hostdev.c
> @@ -29,6 +29,7 @@
> #include "viralloc.h"
> #include "virpci.h"
> #include "virusb.h"
> +#include "virscsi.h"
> #include "virnetdev.h"
>
> #define VIR_FROM_THIS VIR_FROM_QEMU
> @@ -214,6 +215,59 @@ cleanup:
> return ret;
> }
>
> +int
> +qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> +{
> + virDomainHostdevDefPtr hostdev = NULL;
> + int i;
> + int ret = -1;
> +
> + 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)
> + continue;
> + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> + continue;
Can be more compact:
if (hostdev->model != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
continue;
> +
> + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + hostdev->readonly))) {
> + VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain %s",
> + hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + def->name);
> + continue;
> + }
> +
> + virSCSIDeviceSetUsedBy(scsi, def->name);
> +
> + if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
> + virSCSIDeviceFree(scsi);
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to add SCSI device %d:%d:%d:%d to activeScsiHostdevs"),
> + virSCSIDeviceGetAdapter(scsi), virSCSIDeviceGetBus(scsi),
> + virSCSIDeviceGetTarget(scsi), virSCSIDeviceGetUnit(scsi));
> + goto cleanup;
> + }
> + }
> + ret = 0;
> +
> +cleanup:
> + virObjectUnlock(driver->activeScsiHostdevs);
> + return ret;
> +}
> +
> static int
> qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
> {
> @@ -811,6 +865,103 @@ cleanup:
> return ret;
> }
>
> +int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
> + const char *name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + int i, j, count;
> + virSCSIDeviceListPtr list;
> + virSCSIDevicePtr tmp;
> +
> + /* To prevent situation where SCSI device is assigned to two domains
> + * we need to keep a list of currently assigned SCSI devices.
> + * This is done in several loops which cannot be joined into one big
> + * loop. See qemuPrepareHostdevPCIDevices()
> + */
> + if (!(list = virSCSIDeviceListNew()))
> + goto cleanup;
> +
> + /* Loop 1: build temporary list
> + */
/* Loop 1: build temporary list */
> + for (i = 0 ; i < nhostdevs ; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virSCSIDevicePtr scsi;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> + continue;
> +
> + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + hostdev->readonly)))
> + goto cleanup;
> +
> + if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) {
> + virSCSIDeviceFree(scsi);
> + goto cleanup;
> + }
> + }
> +
> + /* Loop 2: Mark devices in temporary list as used by @name
> + * and add them do driver list. However, if something goes
s/do/to/
> + * wrong, perform rollback.
> + */
> + virObjectLock(driver->activeScsiHostdevs);
> + count = virSCSIDeviceListCount(list);
> +
> + for (i = 0; i < count; i++) {
> + virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
> + if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
> + const char *other_name = virSCSIDeviceGetUsedBy(tmp);
> +
> + if (other_name)
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("SCSI device %s is in use by domain %s"),
> + virSCSIDeviceGetName(tmp), other_name);
> + else
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("SCSI device %s is already in use"),
> + virSCSIDeviceGetName(tmp));
> + goto error;
> + }
> +
> + virSCSIDeviceSetUsedBy(scsi, name);
> + VIR_DEBUG("Adding %d:%d:%d:%d dom=%s to activeScsiHostdevs",
> + virSCSIDeviceGetAdapter(scsi), virSCSIDeviceGetBus(scsi),
> + virSCSIDeviceGetTarget(scsi), virSCSIDeviceGetUnit(scsi), name);
> + if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
> + goto error;
> + }
> +
> + virObjectUnlock(driver->activeScsiHostdevs);
> +
> + /* Loop 3: Temporary list was successfully merged with
> + * driver list, so steal all items to avoid freeing them
> + * in cleanup label.
> + */
> + while (virSCSIDeviceListCount(list) > 0) {
> + tmp = virSCSIDeviceListGet(list, 0);
> + virSCSIDeviceListSteal(list, tmp);
> + }
> +
> + virObjectUnref(list);
> + return 0;
> +
> +error:
> + for (j = 0; j < i; j++) {
> + tmp = virSCSIDeviceListGet(list, i);
> + virSCSIDeviceListSteal(driver->activeScsiHostdevs, tmp);
> + }
> + virObjectUnlock(driver->activeScsiHostdevs);
> +cleanup:
> + virObjectUnref(list);
> + return -1;
> +}
> +
> int qemuPrepareHostDevices(virQEMUDriverPtr driver,
> virDomainDefPtr def,
> bool coldBoot)
> @@ -825,6 +976,10 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver,
> if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
> return -1;
>
> + if (qemuPrepareHostdevSCSIDevices(driver, def->name,
> + def->hostdevs, def->nhostdevs) < 0)
> + return -1;
> +
> return 0;
> }
>
> @@ -1009,6 +1164,75 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
> virObjectUnlock(driver->activeUsbHostdevs);
> }
>
> +void
> +qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
> + const char *name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + int i;
> +
> + virObjectLock(driver->activeScsiHostdevs);
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virSCSIDevicePtr scsi, tmp;
> + const char *used_by = NULL;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> + continue;
> + if (hostdev->missing)
> + continue;
These "continues" can be more compact.
> +
> + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + hostdev->readonly))) {
> + VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain %s",
> + 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);
> + continue;
> + }
> +
> + /* Delete only those SCSI devices which belongs
> + * to domain @name because qemuProcessStart() might
> + * have failed because SCSI device is already taken.
s/because/for/
> + * Therefore we want to steal only those devices from
s/steal/delete/
> + * the list which were taken by @name */
s/taken/used/
How about:
/* Only delete the devices which are marked as being used by @name,
* because qemuProcessStart could fail on the half way.
*/
How about one specify (managed='no|yes') for scsi hostdev?
Osier
More information about the libvir-list
mailing list