[libvirt] [PATCH v3.1 00/10] Implementation of QEMU vhost-scsi

This patch series provides a libvirt implementation of the vhost-scsi interface in QEMU. As near as I can see, this was discussed upstream in July 2014[1], and ended in a desire to replace a vhost-scsi controller in favor of a hostdev element instead[2]. Host setup via targetcli (SCSI LUN(s) are already defined to host): # targetcli targetcli shell version 2.1.fb35 Copyright 2011-2013 by Datera, Inc and others. For help on commands, type 'help'. /> backstores/block create write_back=false name=disk1 \ dev=/dev/disk/by-id/dm-name-36005076306ffc7630000000000002211 Created block storage object disk1 using /dev/disk/by-id/dm-name-36005076306ffc7630000000000002211. /> vhost/ create Created target naa.5001405df3e54061. Created TPG 1. /> vhost/naa.5001405df3e54061/tpg1/luns create /backstores/block/disk1 Created LUN 0. /> exit Host Filesystem Example: # ls /sys/kernel/config/target/vhost/ discovery_auth naa.5001405df3e54061 version # ls /sys/kernel/config/target/vhost/naa.5001405df3e54061/tpgt_1/lun/ lun_0 QEMU Example (snippet): -device vhost-scsi-ccw,wwpn=naa.5001405df3e54061,devno=fe.0.1000 Libvirt Example (snippet): <hostdev mode='subsystem' type='scsi_host'> <source protocol='vhost' wwpn='naa.5001405df3e54061'/> <address type='ccw' cssid='0xfe' ssid='0x0' devno='0x1000'/> </hostdev> Guest Viewpoint: # lsscsi [1:0:1:0] disk LIO-ORG disk0 4.0 /dev/sda # dmesg | grep 1: [ 6.065735] scsi host1: Virtio SCSI HBA [ 6.093892] scsi 1:0:1:0: Direct-Access LIO-ORG disk0 4.0 PQ: 0 ANSI: 5 [ 6.313615] sd 1:0:1:0: Attached scsi generic sg0 type 0 [ 6.314981] sd 1:0:1:0: [sda] 29360128 512-byte logical blocks: (15.0 GB/14.0 GiB) [ 6.317290] sd 1:0:1:0: [sda] Write Protect is off [ 6.317566] sd 1:0:1:0: [sda] Mode Sense: 43 00 10 08 [ 6.317853] sd 1:0:1:0: [sda] Write cache: enabled, read cache: enabled, supports DPO and FUA [ 6.352722] sd 1:0:1:0: [sda] Attached SCSI disk Changelog: v3.1: - Rebase - Rebased to current master (31 October) - Included the prereq for the subsystem type in switch statements (oops!) v3: https://www.redhat.com/archives/libvir-list/2016-October/msg01201.html - Rebase - Rebased to current master (26 October) - Comments - Added an early patch to do some additional typecasting in the switch statements of hostdev.subsys.type - Did some reordering of patches, to hopefully flow better - Implemented an activeHostHostdevs list, which is used by the cgroup and security codepaths - doc changes -- s/2.2/2.5/ and s/HBI/HBA/ - Added a "none" protocol type for scsi_host hostdevs (which is invalid) - Restored the apparmor and selinux codepaths that got lost from v1 - Added a proper check for a valid scsi_host protocol, and saving that value within the HostdevDef struct - Fixed a compiler warning with call to virDomainPCIAddressEnsureAddr - Removed the rest of vhostfdSize, since multiple fd's are not allowed by QEMU - Fixed cleanup of vhostfd in error from building -device string - Moved the "conf" chunk from "hotplug" patch to "introduce" patch - Added xml2xml test - Added a proper calculation of "address" in virDomainAuditHostdev - Added a virFileExists check before open(/dev/vhost-scsi) - Addressed a number of lines >80 characters - Things *NOT* done (later?) - Investigation/tie-in with virsh nodedev-list stuff - Implementation of 'num_queues', 'max_sectors', and 'cmd_per_lun' (Need to research these in the virtio space, before figuring out how to apply to vhost-scsi) - Dropping the "naa." prefix of wwn - Split the "tests" patch into earlier patches - Other v2.1: https://www.redhat.com/archives/libvir-list/2016-September/msg00148.html v2: https://www.redhat.com/archives/libvir-list/2016-August/msg01028.html v1: https://www.redhat.com/archives/libvir-list/2016-July/msg01004.html [1] http://www.redhat.com/archives/libvir-list/2014-July/msg01235.html [2] http://www.redhat.com/archives/libvir-list/2014-July/msg01390.html Eric Farman (10): Cleanup switch statements on the hostdev subsystem type qemu: Introduce vhost-scsi capability Introduce a "scsi_host" hostdev type util: Management routines for scsi_host devices qemu: Add vhost-scsi string for -device parameter qemu: Allow hotplug of vhost-scsi device conf: Wire up the vhost-scsi connection from/to XML security: Include vhost-scsi in security labels tests: Introduce basic vhost-scsi test docs: Add vhost-scsi docs/formatdomain.html.in | 24 ++ docs/schemas/domaincommon.rng | 23 ++ src/Makefile.am | 1 + src/conf/domain_audit.c | 7 + src/conf/domain_conf.c | 102 ++++++- src/conf/domain_conf.h | 18 ++ src/libvirt_private.syms | 19 ++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_cgroup.c | 50 +++- src/qemu/qemu_command.c | 79 ++++++ src/qemu/qemu_command.h | 5 + src/qemu/qemu_domain_address.c | 10 + src/qemu/qemu_hostdev.c | 41 +++ src/qemu/qemu_hostdev.h | 8 + src/qemu/qemu_hotplug.c | 160 +++++++++++ src/security/security_apparmor.c | 24 +- src/security/security_dac.c | 46 ++++ src/security/security_selinux.c | 51 +++- src/util/virhost.c | 301 +++++++++++++++++++++ src/util/virhost.h | 72 +++++ src/util/virhostdev.c | 155 +++++++++++ src/util/virhostdev.h | 16 ++ tests/domaincapsschemadata/full.xml | 1 + tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml | 1 + .../caps_2.6.0-gicv2.aarch64.xml | 1 + .../caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml | 1 + .../qemuxml2argv-hostdev-scsi-vhost-scsi.args | 24 ++ .../qemuxml2argv-hostdev-scsi-vhost-scsi.xml | 41 +++ tests/qemuxml2argvmock.c | 9 + tests/qemuxml2argvtest.c | 3 + .../qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml | 1 + tests/qemuxml2xmltest.c | 3 + 41 files changed, 1294 insertions(+), 14 deletions(-) create mode 100644 src/util/virhost.c create mode 100644 src/util/virhost.h create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml -- 1.9.1

As was suggested in an earlier review comment[1], we can catch some additional code points by cleaning up how we use the hostdev subsystem type in some switch statements. [1] End of https://www.redhat.com/archives/libvir-list/2016-September/msg00399.html Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 11 +++++++++-- src/qemu/qemu_cgroup.c | 11 +++++++---- src/security/security_apparmor.c | 4 ++-- src/security/security_selinux.c | 8 ++++---- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 03506cb..7275921 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -12973,7 +12973,7 @@ virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt, } if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { - switch (def->source.subsys.type) { + switch ((virDomainHostdevSubsysType) def->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { @@ -12995,6 +12995,11 @@ virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt, if (virXPathBoolean("boolean(./shareable)", ctxt)) def->shareable = true; break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: + goto error; + break; } } @@ -13861,7 +13866,7 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a, if (a->source.subsys.type != b->source.subsys.type) return 0; - switch (a->source.subsys.type) { + switch ((virDomainHostdevSubsysType) a->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: return virDomainHostdevMatchSubsysPCI(a, b); case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: @@ -13875,6 +13880,8 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a, return virDomainHostdevMatchSubsysSCSIiSCSI(a, b); else return virDomainHostdevMatchSubsysSCSIHost(a, b); + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: + return 0; } return 0; } diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 4489c64..1443f7e 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -301,7 +301,7 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm, if (dev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { - switch (dev->source.subsys.type) { + switch ((virDomainHostdevSubsysType) dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { int rv; @@ -376,7 +376,7 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm, break; } - default: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; } } @@ -410,7 +410,7 @@ qemuTeardownHostdevCgroup(virDomainObjPtr vm, if (dev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { - switch (dev->source.subsys.type) { + switch ((virDomainHostdevSubsysType) dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { int rv; @@ -437,7 +437,10 @@ qemuTeardownHostdevCgroup(virDomainObjPtr vm, case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: /* nothing to tear down for USB */ break; - default: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + /* nothing to tear down for SCSI */ + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; } } diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index af2b639..beddf6d 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -856,7 +856,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, ptr->mgr = mgr; ptr->def = def; - switch (dev->source.subsys.type) { + switch ((virDomainHostdevSubsysType) dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { virUSBDevicePtr usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot); @@ -909,7 +909,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, break; } - default: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; } diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5dad22c..89c93dc 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -1436,7 +1436,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr, scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) return 0; - switch (dev->source.subsys.type) { + switch ((virDomainHostdevSubsysType) dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { virUSBDevicePtr usb; @@ -1498,7 +1498,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr, break; } - default: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; } @@ -1640,7 +1640,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) return 0; - switch (dev->source.subsys.type) { + switch ((virDomainHostdevSubsysType) dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { virUSBDevicePtr usb; @@ -1700,7 +1700,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, break; } - default: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; } -- 1.9.1

Do all the stuff for the vhost-scsi capability in QEMU, so it's in place for our checks later. Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml | 1 + 13 files changed, 14 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7a8202a..d1ce0d9 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -347,6 +347,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "machine-iommu", "virtio-vga", "drive-iotune-max-length", + "vhost-scsi", ); @@ -1588,6 +1589,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "pxb-pcie", QEMU_CAPS_DEVICE_PXB_PCIE }, { "tls-creds-x509", QEMU_CAPS_OBJECT_TLS_CREDS_X509 }, { "intel-iommu", QEMU_CAPS_DEVICE_INTEL_IOMMU }, + { "vhost-scsi", QEMU_CAPS_DEVICE_VHOST_SCSI }, }; static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBalloon[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 6e7a855..89dddf1 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -381,6 +381,7 @@ typedef enum { QEMU_CAPS_MACHINE_IOMMU, /* -machine iommu=on */ QEMU_CAPS_DEVICE_VIRTIO_VGA, /* -device virtio-vga */ QEMU_CAPS_DRIVE_IOTUNE_MAX_LENGTH, /* -drive bps_max_length = and friends */ + QEMU_CAPS_DEVICE_VHOST_SCSI, /* -device vhost-scsi-{ccw,pci} */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml index cc4ffef..2931418 100644 --- a/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml @@ -139,6 +139,7 @@ <flag name='device-tray-moved-event'/> <flag name='nec-usb-xhci-ports'/> <flag name='display'/> + <flag name='vhost-scsi'/> <version>1005003</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml index 8e0e697..15f2075 100644 --- a/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml @@ -144,6 +144,7 @@ <flag name='device-tray-moved-event'/> <flag name='nec-usb-xhci-ports'/> <flag name='display'/> + <flag name='vhost-scsi'/> <version>1006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml index 40acf62..0726443 100644 --- a/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml @@ -146,6 +146,7 @@ <flag name='device-tray-moved-event'/> <flag name='nec-usb-xhci-ports'/> <flag name='display'/> + <flag name='vhost-scsi'/> <version>1007000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml index a8a79af..498e2d0 100644 --- a/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml @@ -161,6 +161,7 @@ <flag name='name-guest'/> <flag name='drive-detect-zeroes'/> <flag name='display'/> + <flag name='vhost-scsi'/> <version>2001001</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml index 3162758..18594e6 100644 --- a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml @@ -181,6 +181,7 @@ <flag name='virtio-pci-disable-legacy'/> <flag name='machine-iommu'/> <flag name='virtio-vga'/> + <flag name='vhost-scsi'/> <version>2004000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml index 62d42c3..a36136d 100644 --- a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml @@ -186,6 +186,7 @@ <flag name='virtio-pci-disable-legacy'/> <flag name='machine-iommu'/> <flag name='virtio-vga'/> + <flag name='vhost-scsi'/> <version>2005000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml index 5c6a709..9ef440f 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml @@ -159,6 +159,7 @@ <flag name='smm'/> <flag name='virtio-pci-disable-legacy'/> <flag name='drive-iotune-max-length'/> + <flag name='vhost-scsi'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml index 6ba97be..25c1995 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml @@ -159,6 +159,7 @@ <flag name='smm'/> <flag name='virtio-pci-disable-legacy'/> <flag name='drive-iotune-max-length'/> + <flag name='vhost-scsi'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml index 9174f58..6c4f863 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml @@ -154,6 +154,7 @@ <flag name='virtio-pci-disable-legacy'/> <flag name='virtio-vga'/> <flag name='drive-iotune-max-length'/> + <flag name='vhost-scsi'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml index 1c309df..827fb55 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml @@ -193,6 +193,7 @@ <flag name='machine-iommu'/> <flag name='virtio-vga'/> <flag name='drive-iotune-max-length'/> + <flag name='vhost-scsi'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml index 2f168da..4eaf7c8 100644 --- a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml @@ -194,6 +194,7 @@ <flag name='query-hotpluggable-cpus'/> <flag name='virtio-vga'/> <flag name='drive-iotune-max-length'/> + <flag name='vhost-scsi'/> <version>2007000</version> <kvmVersion>0</kvmVersion> <package> (v2.7.0)</package> -- 1.9.1

We already have a "scsi" hostdev type, which refers to a single LUN that is passed through to a guest. But what of things where multiple LUNs are passed through via a single SCSI HBA, such as with the vhost-scsi target? Create a new hostdev type that will carry this. Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 12 +++++++++++- src/conf/domain_conf.h | 18 ++++++++++++++++++ src/qemu/qemu_cgroup.c | 7 +++++++ src/qemu/qemu_hotplug.c | 2 ++ src/security/security_apparmor.c | 4 ++++ src/security/security_dac.c | 8 ++++++++ src/security/security_selinux.c | 8 ++++++++ tests/domaincapsschemadata/full.xml | 1 + 8 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7275921..08c4f8b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -647,7 +647,8 @@ VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST, VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST, "usb", "pci", - "scsi") + "scsi", + "scsi_host") VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend, VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST, @@ -661,6 +662,11 @@ VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIProtocol, "adapter", "iscsi") +VIR_ENUM_IMPL(virDomainHostdevSubsysHostProtocol, + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_LAST, + "none", + "vhost") + VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST, "storage", "misc", @@ -12997,6 +13003,8 @@ virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt, break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: goto error; break; @@ -13880,6 +13888,8 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a, return virDomainHostdevMatchSubsysSCSIiSCSI(a, b); else return virDomainHostdevMatchSubsysSCSIHost(a, b); + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + /* Fall through for now */ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: return 0; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 24aa79c..2870035 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -294,6 +294,7 @@ typedef enum { VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI, + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST } virDomainHostdevSubsysType; @@ -368,6 +369,22 @@ struct _virDomainHostdevSubsysSCSI { } u; }; +typedef enum { + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_NONE, + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST, + + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_LAST, +} virDomainHostdevSubsysHostProtocolType; + +VIR_ENUM_DECL(virDomainHostdevSubsysHostProtocol) + +typedef struct _virDomainHostdevSubsysHost virDomainHostdevSubsysHost; +typedef virDomainHostdevSubsysHost *virDomainHostdevSubsysHostPtr; +struct _virDomainHostdevSubsysHost { + int protocol; + char *wwpn; +}; + typedef struct _virDomainHostdevSubsys virDomainHostdevSubsys; typedef virDomainHostdevSubsys *virDomainHostdevSubsysPtr; struct _virDomainHostdevSubsys { @@ -376,6 +393,7 @@ struct _virDomainHostdevSubsys { virDomainHostdevSubsysUSB usb; virDomainHostdevSubsysPCI pci; virDomainHostdevSubsysSCSI scsi; + virDomainHostdevSubsysHost host; } u; }; diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 1443f7e..ee31d14 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -376,6 +376,10 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm, break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + break; + } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; } @@ -440,6 +444,9 @@ qemuTeardownHostdevCgroup(virDomainObjPtr vm, case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: /* nothing to tear down for SCSI */ break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + /* nothing to tear down for scsi_host */ + break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 9746a06..335252b 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -3510,6 +3510,8 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver, case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev); break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; } diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index beddf6d..e7e3c8c 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -909,6 +909,10 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + /* Fall through for now */ + } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index fd74e8b..eba2a87 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -676,6 +676,10 @@ virSecurityDACSetHostdevLabel(virSecurityManagerPtr mgr, break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + /* Fall through for now */ + } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; @@ -805,6 +809,10 @@ virSecurityDACRestoreHostdevLabel(virSecurityManagerPtr mgr, break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + /* Fall through for now */ + } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 89c93dc..a94bba3 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -1498,6 +1498,10 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr, break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + /* Fall through for now */ + } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; @@ -1700,6 +1704,10 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + /* Fall through for now */ + } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: ret = 0; break; diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml index eaf6eb6..6abd499 100644 --- a/tests/domaincapsschemadata/full.xml +++ b/tests/domaincapsschemadata/full.xml @@ -87,6 +87,7 @@ <value>usb</value> <value>pci</value> <value>scsi</value> + <value>scsi_host</value> </enum> <enum name='capsType'> <value>storage</value> -- 1.9.1

Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- src/Makefile.am | 1 + src/libvirt_private.syms | 19 +++ src/util/virhost.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhost.h | 72 ++++++++++++ src/util/virhostdev.c | 155 ++++++++++++++++++++++++ src/util/virhostdev.h | 16 +++ tests/qemuxml2argvmock.c | 9 ++ 7 files changed, 573 insertions(+) create mode 100644 src/util/virhost.c create mode 100644 src/util/virhost.h diff --git a/src/Makefile.am b/src/Makefile.am index 8ee5567..11b7dc4 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 b4210f4..c152e76 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1671,6 +1671,23 @@ virHookInitialize; virHookPresent; +# util/virhost.h +virHostDeviceFileIterate; +virHostDeviceFree; +virHostDeviceGetName; +virHostDeviceListAdd; +virHostDeviceListCount; +virHostDeviceListDel; +virHostDeviceListFind; +virHostDeviceListFindIndex; +virHostDeviceListGet; +virHostDeviceListNew; +virHostDeviceListSteal; +virHostDeviceNew; +virHostDeviceSetUsedBy; +virHostOpenVhostSCSI; + + # util/virhostdev.h virHostdevFindUSBDevice; virHostdevManagerGetDefault; @@ -1678,10 +1695,12 @@ virHostdevPCINodeDeviceDetach; virHostdevPCINodeDeviceReAttach; virHostdevPCINodeDeviceReset; virHostdevPrepareDomainDevices; +virHostdevPrepareHostDevices; 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..dd0d982 --- /dev/null +++ b/src/util/virhost.c @@ -0,0 +1,301 @@ +/* + * virscsi.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@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; + +struct _virHostDevice { + 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 */ +}; + +struct _virHostDeviceList { + virObjectLockable parent; + size_t count; + virHostDevicePtr *devs; +}; + +static virClassPtr virHostDeviceListClass; + +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); +} + + +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) +{ + 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; + + 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 +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; +} + +int +virHostDeviceSetUsedBy(virHostDevicePtr dev, + const char *drvname, + const char *domname) +{ + 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) +{ + if (!dev) + return; + VIR_DEBUG("%s: freeing", dev->name); + 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@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; +}; + +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); +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 { + 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); + 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; + } + + /* 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; }; 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, -- 1.9.1

Open /dev/vhost-scsi, and record the resulting file descriptor, so that the guest has access to the host device outside of the libvirt daemon. Pass this information, along with data parsed from the XML file, to build a device string for the qemu command line. That device string will be for either a vhost-scsi-ccw device in the case of an s390 machine, or vhost-scsi-pci for any others. Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- src/qemu/qemu_cgroup.c | 32 +++++++++++++++++ src/qemu/qemu_command.c | 79 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_command.h | 5 +++ src/qemu/qemu_domain_address.c | 10 ++++++ src/qemu/qemu_hostdev.c | 41 ++++++++++++++++++++++ src/qemu/qemu_hostdev.h | 8 +++++ 6 files changed, 175 insertions(+) diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index ee31d14..a22a1bf 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -277,6 +277,25 @@ qemuSetupHostSCSIDeviceCgroup(virSCSIDevicePtr dev ATTRIBUTE_UNUSED, return ret; } +static int +qemuSetupHostHostDeviceCgroup(virHostDevicePtr dev ATTRIBUTE_UNUSED, + const char *path, + void *opaque) +{ + virDomainObjPtr vm = opaque; + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret; + + VIR_DEBUG("Process path '%s' for scsi_host device", path); + + ret = virCgroupAllowDevicePath(priv->cgroup, path, + VIR_CGROUP_DEVICE_RW, false); + + virDomainAuditCgroupPath(vm, priv->cgroup, "allow", path, "rw", ret == 0); + + return ret; +} + int qemuSetupHostdevCgroup(virDomainObjPtr vm, virDomainHostdevDefPtr dev) @@ -286,9 +305,11 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm, virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; virPCIDevicePtr pci = NULL; virUSBDevicePtr usb = NULL; virSCSIDevicePtr scsi = NULL; + virHostDevicePtr host = NULL; char *path = NULL; /* currently this only does something for PCI devices using vfio @@ -377,6 +398,16 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm, } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { + if (hostsrc->protocol == + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST) { + if ((host = virHostDeviceNew(hostsrc->wwpn)) == NULL) + goto cleanup; + + if (virHostDeviceFileIterate(host, + qemuSetupHostHostDeviceCgroup, + vm) < 0) + goto cleanup; + } break; } @@ -390,6 +421,7 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm, virPCIDeviceFree(pci); virUSBDeviceFree(usb); virSCSIDeviceFree(scsi); + virHostDeviceFree(host); VIR_FREE(path); return ret; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b68da3d..4e946ea 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4722,6 +4722,43 @@ qemuBuildSCSIiSCSIHostdevDrvStr(virDomainHostdevDefPtr dev) } char * +qemuBuildHostHostdevDevStr(const virDomainDef *def, + virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps, + char *vhostfdName) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_SCSI)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("This QEMU doesn't support vhost-scsi devices")); + goto cleanup; + } + + if (ARCH_IS_S390(def->os.arch)) + virBufferAddLit(&buf, "vhost-scsi-ccw"); + else + virBufferAddLit(&buf, "vhost-scsi-pci"); + + virBufferAsprintf(&buf, ",wwpn=%s", hostsrc->wwpn); + virBufferAsprintf(&buf, ",vhostfd=%s", vhostfdName); + virBufferAsprintf(&buf, ",id=%s", dev->info->alias); + + if (qemuBuildDeviceAddressStr(&buf, def, dev->info, qemuCaps) < 0) + goto cleanup; + + if (virBufferCheckError(&buf) < 0) + goto cleanup; + + return virBufferContentAndReset(&buf); + + cleanup: + virBufferFreeAndReset(&buf); + return NULL; +} + +char * qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -5202,6 +5239,48 @@ qemuBuildHostdevCommandLine(virCommandPtr cmd, return -1; } } + + /* SCSI_host */ + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + subsys->type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("SCSI passthrough is not supported by this " + "version of qemu")); + return -1; + } + + if (hostdev->source.subsys.u.host.protocol == + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST) { + char *vhostfdName = NULL; + int vhostfd = -1; + + if (virHostOpenVhostSCSI(&vhostfd) < 0) + return -1; + + if (virAsprintf(&vhostfdName, "%d", vhostfd) < 0) { + VIR_FORCE_CLOSE(vhostfd); + return -1; + } + + virCommandPassFD(cmd, vhostfd, + VIR_COMMAND_PASS_FD_CLOSE_PARENT); + + virCommandAddArg(cmd, "-device"); + if (!(devstr = qemuBuildHostHostdevDevStr(def, + hostdev, + qemuCaps, + vhostfdName))) { + VIR_FREE(vhostfdName); + VIR_FORCE_CLOSE(vhostfd); + return -1; + } + virCommandAddArg(cmd, devstr); + + VIR_FREE(vhostfdName); + VIR_FREE(devstr); + } + } } return 0; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index a793fb6..c6efe11 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -163,6 +163,11 @@ char *qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev); char *qemuBuildSCSIHostdevDevStr(const virDomainDef *def, virDomainHostdevDefPtr dev, virQEMUCapsPtr qemuCaps); +char * +qemuBuildHostHostdevDevStr(const virDomainDef *def, + virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps, + char *vhostfdName); char *qemuBuildRedirdevDevStr(const virDomainDef *def, virDomainRedirdevDefPtr dev, diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index e206b9f..90adcbc 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -310,6 +310,16 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDefPtr def, } } + for (i = 0; i < def->nhostdevs; i++) { + if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + def->hostdevs[i]->source.subsys.type == + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST && + def->hostdevs[i]->source.subsys.u.host.protocol == + VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST && + def->hostdevs[i]->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) + def->hostdevs[i]->info->type = type; + } + if (def->memballoon && def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO && def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index dd3a3cf..29aedeb 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -292,6 +292,17 @@ qemuHostdevPrepareSCSIDevices(virQEMUDriverPtr driver, name, hostdevs, nhostdevs); } +int +qemuHostdevPrepareHostDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr; + + return virHostdevPrepareHostDevices(hostdev_mgr, QEMU_DRIVER_NAME, + name, hostdevs, nhostdevs); +} int qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver, @@ -315,6 +326,10 @@ qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver, def->hostdevs, def->nhostdevs) < 0) return -1; + if (qemuHostdevPrepareHostDevices(driver, def->name, + def->hostdevs, def->nhostdevs) < 0) + return -1; + return 0; } @@ -370,6 +385,29 @@ qemuHostdevReAttachSCSIDevices(virQEMUDriverPtr driver, } void +qemuHostdevReAttachHostDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virDomainDeviceDef dev; + + dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; + dev.data.hostdev = hostdev; + + ignore_value(qemuRemoveSharedDevice(driver, &dev, name)); + } + + virHostdevReAttachHostDevices(hostdev_mgr, QEMU_DRIVER_NAME, + name, hostdevs, nhostdevs); +} + +void qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver, virDomainDefPtr def) { @@ -384,4 +422,7 @@ qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver, qemuHostdevReAttachSCSIDevices(driver, def->name, def->hostdevs, def->nhostdevs); + + qemuHostdevReAttachHostDevices(driver, def->name, def->hostdevs, + def->nhostdevs); } diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index 0a3c715..1788d12 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -55,6 +55,10 @@ int qemuHostdevPrepareSCSIDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); +int qemuHostdevPrepareHostDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); int qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, @@ -72,6 +76,10 @@ void qemuHostdevReAttachSCSIDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); +void qemuHostdevReAttachHostDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); void qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver, virDomainDefPtr def); -- 1.9.1

Adjust the device string that is built for vhost-scsi devices so that it can be invoked from hotplug.
From the QEMU command line, the file descriptors are expect to be numeric only. However, for hotplug, the file descriptors are expected to begin with at least one alphabetic character else this error occurs:
# virsh attach-device guest_0001 ~/vhost.xml error: Failed to attach device from /root/vhost.xml error: internal error: unable to execute QEMU command 'getfd': Parameter 'fdname' expects a name not starting with a digit We also close the file descriptor in this case, so that shutting down the guest cleans up the host cgroup entries and allows future guests to use vhost-scsi devices. (Otherwise the guest will silently end.) Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- src/qemu/qemu_hotplug.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 335252b..33e55e3 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2434,6 +2434,120 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn, goto cleanup; } +static int +qemuDomainAttachHostSCSIHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + int ret = -1; + qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainCCWAddressSetPtr ccwaddrs = NULL; + char *vhostfdName = NULL; + int vhostfd = -1; + char *devstr = NULL; + bool teardowncgroup = false; + bool teardownlabel = false; + bool releaseaddr = false; + + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("SCSI passthrough is not supported by this version of qemu")); + goto cleanup; + } + + if (qemuHostdevPrepareHostDevices(driver, vm->def->name, &hostdev, 1) < 0) { + virDomainHostdevSubsysHostPtr hostsrc = &hostdev->source.subsys.u.host; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to prepare scsi_host hostdev: %s"), + hostsrc->wwpn); + goto cleanup; + } + + if (qemuSetupHostdevCgroup(vm, hostdev) < 0) + goto cleanup; + teardowncgroup = true; + + if (virSecurityManagerSetHostdevLabel(driver->securityManager, + vm->def, hostdev, NULL) < 0) + goto cleanup; + teardownlabel = true; + + if (virHostOpenVhostSCSI(&vhostfd) < 0) + goto cleanup; + + if (virAsprintf(&vhostfdName, "vhostfd-%d", vhostfd) < 0) + goto cleanup; + + if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + if (qemuDomainMachineIsS390CCW(vm->def) && + virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) + hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW; + } + + if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE || + hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0) + goto cleanup; + } else if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) { + if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def))) + goto cleanup; + if (virDomainCCWAddressAssign(hostdev->info, ccwaddrs, + !hostdev->info->addr.ccw.assigned) < 0) + goto cleanup; + } + releaseaddr = true; + + if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0) + goto cleanup; + + if (!(devstr = qemuBuildHostHostdevDevStr(vm->def, + hostdev, + priv->qemuCaps, + vhostfdName))) + goto cleanup; + + qemuDomainObjEnterMonitor(driver, vm); + + ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr, vhostfd, vhostfdName); + + if (qemuDomainObjExitMonitor(driver, vm) < 0) { + ret = -1; + goto cleanup; + } + + virDomainAuditHostdev(vm, hostdev, "attach", (ret == 0)); + + if (ret < 0) + goto cleanup; + + if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0) + goto cleanup; + + vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; + + virDomainCCWAddressSetFree(ccwaddrs); + + VIR_FORCE_CLOSE(vhostfd); + VIR_FREE(vhostfdName); + VIR_FREE(devstr); + return 0; + + cleanup: + if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0) + VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail"); + if (teardownlabel && + virSecurityManagerRestoreHostdevLabel(driver->securityManager, + vm->def, hostdev, NULL) < 0) + VIR_WARN("Unable to restore host device labelling on hotplug fail"); + if (releaseaddr) + qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL); + + VIR_FORCE_CLOSE(vhostfd); + VIR_FREE(vhostfdName); + VIR_FREE(devstr); + return ret; +} + int qemuDomainAttachHostDevice(virConnectPtr conn, @@ -2467,6 +2581,11 @@ qemuDomainAttachHostDevice(virConnectPtr conn, goto error; break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + if (qemuDomainAttachHostSCSIHostDevice(driver, vm, hostdev) < 0) + goto error; + break; + default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("hostdev subsys type '%s' not supported"), @@ -3433,6 +3552,14 @@ qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver, qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1); } +static void +qemuDomainRemoveHostSCSIHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + qemuHostdevReAttachHostDevices(driver, vm->def->name, &hostdev, 1); +} + static int qemuDomainRemoveHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -3511,6 +3638,7 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver, qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev); break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + qemuDomainRemoveHostSCSIHostDevice(driver, vm, hostdev); break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; @@ -4302,6 +4430,31 @@ qemuDomainDetachHostSCSIDevice(virQEMUDriverPtr driver, } static int +qemuDomainDetachHostSCSIHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr detach) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret = -1; + + if (!detach->info->alias) { + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("device cannot be detached without a device alias")); + return -1; + } + + qemuDomainMarkDeviceForRemoval(vm, detach->info); + + qemuDomainObjEnterMonitor(driver, vm); + ret = qemuMonitorDelDevice(priv->mon, detach->info->alias); + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + + return ret; +} + +static int qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainHostdevDefPtr detach) @@ -4323,6 +4476,9 @@ qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver, case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: ret = qemuDomainDetachHostSCSIDevice(driver, vm, detach); break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + ret = qemuDomainDetachHostSCSIHostDevice(driver, vm, detach); + break; default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("hostdev subsys type '%s' not supported"), @@ -4400,6 +4556,8 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver, } break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + break; default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected hostdev type %d"), subsys->type); -- 1.9.1

Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- docs/schemas/domaincommon.rng | 23 ++++++++++++ src/conf/domain_audit.c | 7 ++++ src/conf/domain_conf.c | 81 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index dba9187..ad5d55d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3963,6 +3963,7 @@ <ref name="hostdevsubsyspci"/> <ref name="hostdevsubsysusb"/> <ref name="hostdevsubsysscsi"/> + <ref name="hostdevsubsyshost"/> </choice> </define> @@ -4091,6 +4092,28 @@ </element> </define> + <define name="hostdevsubsyshost"> + <attribute name="type"> + <value>scsi_host</value> + </attribute> + <element name="source"> + <choice> + <group> + <attribute name="protocol"> + <choice> + <value>vhost</value> <!-- vhost, required --> + </choice> + </attribute> + <attribute name="wwpn"> + <data type="string"> + <param name="pattern">(naa\.)[0-9a-fA-F]{16}</param> + </data> + </attribute> + </group> + </choice> + </element> + </define> + <define name="hostdevcapsstorage"> <attribute name="type"> <value>storage</value> diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 2decf02..844b3cd 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -392,6 +392,7 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev, virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &hostdev->source.subsys.u.host; virUUIDFormat(vm->def->uuid, uuidstr); if (!(vmname = virAuditEncode("vm", vm->def->name))) { @@ -444,6 +445,12 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev, } break; } + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + if (VIR_STRDUP_QUIET(address, hostsrc->wwpn) < 0) { + VIR_WARN("OOM while encoding audit message"); + goto cleanup; + } + break; default: VIR_WARN("Unexpected hostdev type while encoding audit message: %d", hostdev->source.subsys.type); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 08c4f8b..79cf32e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2318,6 +2318,9 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def) } else { VIR_FREE(scsisrc->u.host.adapter); } + } else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST) { + virDomainHostdevSubsysHostPtr hostsrc = &def->source.subsys.u.host; + VIR_FREE(hostsrc->wwpn); } break; } @@ -6087,6 +6090,55 @@ virDomainHostdevSubsysSCSIDefParseXML(xmlNodePtr sourcenode, return ret; } +static int +virDomainHostdevSubsysHostDefParseXML(xmlNodePtr sourcenode, + virDomainHostdevDefPtr def) +{ + char *protocol = NULL; + virDomainHostdevSubsysHostPtr hostsrc = &def->source.subsys.u.host; + + if ((protocol = virXMLPropString(sourcenode, "protocol"))) { + hostsrc->protocol = + virDomainHostdevSubsysHostProtocolTypeFromString(protocol); + if (hostsrc->protocol <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown scsi_host subsystem protocol '%s'"), + protocol); + goto cleanup; + } + } + + switch ((virDomainHostdevSubsysHostProtocolType) hostsrc->protocol) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_VHOST: + if (!(hostsrc->wwpn = virXMLPropString(sourcenode, "wwpn"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing vhost-scsi hostdev source path name")); + goto cleanup; + } + + if (!STRPREFIX(hostsrc->wwpn, "naa.") || + strlen(hostsrc->wwpn) != strlen("naa.") + 16) { + virReportError(VIR_ERR_XML_ERROR, "%s", _("malformed 'wwpn' value")); + goto cleanup; + } + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_NONE: + case VIR_DOMAIN_HOSTDEV_SUBSYS_HOST_PROTOCOL_TYPE_LAST: + virReportError(VIR_ERR_XML_ERROR, + _("Invalid hostdev protocol '%s'"), + virDomainHostdevSubsysHostProtocolTypeToString(def->source.subsys.type)); + goto cleanup; + break; + } + + return 0; + + cleanup: + VIR_FREE(hostsrc->wwpn); + VIR_FREE(protocol); + return -1; +} + static int virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, @@ -6211,6 +6263,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, goto error; break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + if (virDomainHostdevSubsysHostDefParseXML(sourcenode, def) < 0) + goto error; + break; + default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("address type='%s' not supported in hostdev interfaces"), @@ -13889,7 +13946,13 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a, else return virDomainHostdevMatchSubsysSCSIHost(a, b); case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: - /* Fall through for now */ + if (a->source.subsys.u.host.protocol != + b->source.subsys.u.host.protocol) + return 0; + if (STREQ(a->source.subsys.u.host.wwpn, b->source.subsys.u.host.wwpn)) + return 1; + else + return 0; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: return 0; } @@ -20784,9 +20847,11 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, unsigned int flags, bool includeTypeInAddr) { + bool closedSource = false; virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &def->source.subsys.u.host; virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host; virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi; @@ -20827,6 +20892,15 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, protocol, iscsisrc->path); } + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST) { + const char *protocol = + virDomainHostdevSubsysHostProtocolTypeToString(hostsrc->protocol); + closedSource = true; + + virBufferAsprintf(buf, " protocol='%s' wwpn='%s'/", + protocol, hostsrc->wwpn); + } + virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); @@ -20880,6 +20954,8 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, scsihostsrc->unit); } break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: + break; default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected hostdev type %d"), @@ -20895,7 +20971,8 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, } virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "</source>\n"); + if (!closedSource) + virBufferAddLit(buf, "</source>\n"); return 0; } -- 1.9.1

Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- src/security/security_apparmor.c | 18 ++++++++++++++++- src/security/security_dac.c | 42 ++++++++++++++++++++++++++++++++++++++-- src/security/security_selinux.c | 39 +++++++++++++++++++++++++++++++++++-- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index e7e3c8c..d7bc7d1 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -44,6 +44,7 @@ #include "viruuid.h" #include "virpci.h" #include "virusb.h" +#include "virhost.h" #include "virfile.h" #include "configmake.h" #include "vircommand.h" @@ -357,6 +358,13 @@ AppArmorSetSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED, return AppArmorSetSecurityHostdevLabelHelper(file, opaque); } +static int +AppArmorSetSecurityHostLabel(virHostDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, void *opaque) +{ + return AppArmorSetSecurityHostdevLabelHelper(file, opaque); +} + /* Called on libvirtd startup to see if AppArmor is available */ static int AppArmorSecurityManagerProbe(const char *virtDriver ATTRIBUTE_UNUSED) @@ -831,6 +839,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; if (!secdef) return -1; @@ -910,7 +919,14 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { - /* Fall through for now */ + virHostDevicePtr host = virHostDeviceNew(hostsrc->wwpn); + + if (!host) + goto done; + + ret = virHostDeviceFileIterate(host, AppArmorSetSecurityHostLabel, ptr); + virHostDeviceFree(host); + break; } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: diff --git a/src/security/security_dac.c b/src/security/security_dac.c index eba2a87..accb965 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -36,6 +36,7 @@ #include "virpci.h" #include "virusb.h" #include "virscsi.h" +#include "virhost.h" #include "virstoragefile.h" #include "virstring.h" #include "virutil.h" @@ -582,6 +583,15 @@ virSecurityDACSetSCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED, static int +virSecurityDACSetHostLabel(virHostDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, + void *opaque) +{ + return virSecurityDACSetHostdevLabelHelper(file, opaque); +} + + +static int virSecurityDACSetHostdevLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, virDomainHostdevDefPtr dev, @@ -592,6 +602,7 @@ virSecurityDACSetHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; int ret = -1; if (!priv->dynamicOwnership) @@ -677,7 +688,14 @@ virSecurityDACSetHostdevLabel(virSecurityManagerPtr mgr, } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { - /* Fall through for now */ + virHostDevicePtr host = virHostDeviceNew(hostsrc->wwpn); + + if (!host) + goto done; + + ret = virHostDeviceFileIterate(host, virSecurityDACSetHostLabel, &cbdata); + virHostDeviceFree(host); + break; } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: @@ -724,6 +742,17 @@ virSecurityDACRestoreSCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED, static int +virSecurityDACRestoreHostLabel(virHostDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, + void *opaque) +{ + virSecurityManagerPtr mgr = opaque; + virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + return virSecurityDACRestoreFileLabel(priv, file); +} + + +static int virSecurityDACRestoreHostdevLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, virDomainHostdevDefPtr dev, @@ -735,6 +764,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; int ret = -1; secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); @@ -810,7 +840,15 @@ virSecurityDACRestoreHostdevLabel(virSecurityManagerPtr mgr, } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { - /* Fall through for now */ + virHostDevicePtr host = virHostDeviceNew(hostsrc->wwpn); + + if (!host) + goto done; + + ret = virHostDeviceFileIterate(host, virSecurityDACRestoreHostLabel, mgr); + virHostDeviceFree(host); + + break; } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index a94bba3..0831582 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -39,6 +39,7 @@ #include "virpci.h" #include "virusb.h" #include "virscsi.h" +#include "virhost.h" #include "virstoragefile.h" #include "virfile.h" #include "virhash.h" @@ -1416,6 +1417,13 @@ virSecuritySELinuxSetSCSILabel(virSCSIDevicePtr dev, } static int +virSecuritySELinuxSetHostLabel(virHostDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, void *opaque) +{ + return virSecuritySELinuxSetHostdevLabelHelper(file, opaque); +} + +static int virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, virDomainHostdevDefPtr dev, @@ -1425,6 +1433,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr, virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; virSecuritySELinuxCallbackData data = {.mgr = mgr, .def = def}; int ret = -1; @@ -1499,7 +1508,14 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr, } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { - /* Fall through for now */ + virHostDevicePtr host = virHostDeviceNew(hostsrc->wwpn); + + if (!host) + goto done; + + ret = virHostDeviceFileIterate(host, virSecuritySELinuxSetHostLabel, &data); + virHostDeviceFree(host); + break; } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: @@ -1627,6 +1643,16 @@ virSecuritySELinuxRestoreSCSILabel(virSCSIDevicePtr dev, } static int +virSecuritySELinuxRestoreHostLabel(virHostDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, + void *opaque) +{ + virSecurityManagerPtr mgr = opaque; + + return virSecuritySELinuxRestoreFileLabel(mgr, file); +} + +static int virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev, const char *vroot) @@ -1635,6 +1661,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb; virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysHostPtr hostsrc = &dev->source.subsys.u.host; int ret = -1; /* Like virSecuritySELinuxRestoreImageLabelInt() for a networked @@ -1705,7 +1732,15 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST: { - /* Fall through for now */ + virHostDevicePtr host = virHostDeviceNew(hostsrc->wwpn); + + if (!host) + goto done; + + ret = virHostDeviceFileIterate(host, virSecuritySELinuxRestoreHostLabel, mgr); + virHostDeviceFree(host); + + break; } case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: -- 1.9.1

These tests were cloned from hostdev-scsi-virtio-scsi in both xml2argv and xml2xml Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- .../qemuxml2argv-hostdev-scsi-vhost-scsi.args | 24 +++++++++++++ .../qemuxml2argv-hostdev-scsi-vhost-scsi.xml | 41 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 3 ++ .../qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml | 1 + tests/qemuxml2xmltest.c | 3 ++ 5 files changed, 72 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.args new file mode 100644 index 0000000..5cd2939 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.args @@ -0,0 +1,24 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu \ +-name QEMUGuest2 \ +-S \ +-M pc \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9466-926a-d65c16db1809 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-QEMUGuest2/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest2,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \ +-device vhost-scsi-pci,wwpn=naa.5123456789abcde0,vhostfd=3,id=hostdev0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.xml new file mode 100644 index 0000000..4d57fb8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.xml @@ -0,0 +1,41 @@ +<domain type='qemu'> + <name>QEMUGuest2</name> + <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest2'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <hostdev mode='subsystem' type='scsi_host' managed='no'> + <source protocol='vhost' wwpn='naa.5123456789abcde0'/> + </hostdev> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 90d6aaf..1b3f375 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1886,6 +1886,9 @@ mymain(void) DO_TEST("hostdev-scsi-virtio-iscsi-auth", QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_SCSI_GENERIC); + DO_TEST("hostdev-scsi-vhost-scsi", + QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_VHOST_SCSI, + QEMU_CAPS_DEVICE_SCSI_GENERIC); DO_TEST("mlock-on", QEMU_CAPS_REALTIME_MLOCK); DO_TEST_FAILURE("mlock-on", NONE); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml new file mode 120000 index 0000000..76ebe4c --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-scsi-vhost-scsi.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/qemuxml2argv-hostdev-scsi-vhost-scsi.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 496ed13..261b888 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -737,6 +737,9 @@ mymain(void) QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_HDA_DUPLEX); + DO_TEST("hostdev-scsi-vhost-scsi", + QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_VHOST_SCSI, + QEMU_CAPS_DEVICE_SCSI_GENERIC); DO_TEST("hostdev-scsi-lsi", QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_SCSI_LSI, QEMU_CAPS_DEVICE_SCSI_GENERIC); -- 1.9.1

Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com> --- docs/formatdomain.html.in | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index c70377b..6ef864f 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -3694,6 +3694,17 @@ </devices> ...</pre> + <p>or:</p> + +<pre> + ... + <devices> + <hostdev mode='subsystem' type='scsi_host'> + <source protocol='vhost' wwpn='naa.50014057667280d8'/> + </hostdev> + </devices> + ...</pre> + <dl> <dt><code>hostdev</code></dt> <dd>The <code>hostdev</code> element is the main container for describing @@ -3732,6 +3743,12 @@ If a disk lun in the domain already has the rawio capability, then this setting not required. </dd> + <dt><code>scsi_host</code></dt> + <dd><span class="since">since 2.5.0</span>For SCSI devices, user + is responsible to make sure the device is not used by host. This + <code>type</code> passes all LUNs presented by a single HBA to + the guest. + </dd> </dl> <p> Note: The <code>managed</code> attribute is only used with PCI devices @@ -3795,6 +3812,13 @@ credentials to the iSCSI server. </p> </dd> + <dt><code>scsi_host</code></dt> + <dd><span class="since">Since 2.5.0</span>, multiple LUNs behind a + single SCSI HBA are described by a <code>protocol</code> + attribute set to "vhost" and a <code>wwpn</code> attribute that + is the vhost_scsi wwpn (16 hexadecimal digits with a prefix of + "naa.") established in the host configfs. + </dd> </dl> </dd> <dt><code>vendor</code>, <code>product</code></dt> -- 1.9.1
participants (1)
-
Eric Farman