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(a)linux.vnet.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_command.h | 5 ++++
src/util/virscsi.c | 26 +++++++++++++++++++
src/util/virscsi.h | 1 +
5 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 9396c4e..b91c7a8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2253,6 +2253,7 @@ virSCSIDeviceListNew;
virSCSIDeviceListSteal;
virSCSIDeviceNew;
virSCSIDeviceSetUsedBy;
+virSCSIOpenVhost;
# util/virseclabel.h
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index dd15ff8..31b30a4 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4533,6 +4533,67 @@ qemuBuildSCSIiSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
}
char *
+qemuBuildSCSIVhostHostdevDevStr(const virDomainDef *def,
+ virDomainHostdevDefPtr dev,
+ virQEMUCapsPtr qemuCaps,
+ virCommandPtr cmd)
+{
+ size_t i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
+ virDomainHostdevSubsysSCSIVhostPtr vhostsrc = &scsisrc->u.vhost;
+ int *vhostfd = NULL;
+ size_t vhostfdSize = 1;
+
+ 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", vhostsrc->wwpn);
+
+ if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
+ goto cleanup;
+
+ memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
+
+ if (virSCSIOpenVhost(vhostfd, &vhostfdSize) < 0)
+ goto cleanup;
+
+ for (i = 0; i < vhostfdSize; i++) {
+ if (cmd) {
+ virCommandPassFD(cmd, vhostfd[i],
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+ }
+ }
+
+ if (vhostfdSize == 1) {
+ virBufferAsprintf(&buf, ",vhostfd=%d", vhostfd[0]);
+ } else {
+ /* FIXME if 'vhostfds' became a valid vhost-scsi property in QEMU */
+ goto cleanup;
+ }
+
+ virBufferAsprintf(&buf, ",id=%s", dev->info->alias);
+
+ VIR_FREE(vhostfd);
+ return virBufferContentAndReset(&buf);
+
+ cleanup:
+ for (i = 0; vhostfd && i < vhostfdSize; i++)
+ VIR_FORCE_CLOSE(vhostfd[i]);
+ VIR_FREE(vhostfd);
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+char *
qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -4954,7 +5015,11 @@ qemuBuildHostdevCommandLine(virCommandPtr cmd,
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
subsys->type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
- if (hostdev->source.subsys.u.scsi.protocol !=
VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_VHOST) {
+ if (hostdev->source.subsys.u.scsi.protocol ==
VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_VHOST) {
+ virCommandAddArg(cmd, "-device");
+ if (!(devstr = qemuBuildSCSIVhostHostdevDevStr(def, hostdev,
qemuCaps, cmd)))
+ return -1;
+ } else {
char *drvstr;
virCommandAddArg(cmd, "-drive");
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index c4d0567..5c2dcb0 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -159,6 +159,11 @@ char *qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev);
char *qemuBuildSCSIHostdevDevStr(const virDomainDef *def,
virDomainHostdevDefPtr dev,
virQEMUCapsPtr qemuCaps);
+char *
+qemuBuildSCSIVhostHostdevDevStr(const virDomainDef *def,
+ virDomainHostdevDefPtr dev,
+ virQEMUCapsPtr qemuCaps,
+ virCommandPtr cmd);
char *qemuBuildRedirdevDevStr(const virDomainDef *def,
virDomainRedirdevDefPtr dev,
diff --git a/src/util/virscsi.c b/src/util/virscsi.c
index 4843367..290b692 100644
--- a/src/util/virscsi.c
+++ b/src/util/virscsi.c
@@ -105,6 +105,32 @@ virSCSIDeviceGetAdapterId(const char *adapter,
return -1;
}
+int
+virSCSIOpenVhost(int *vhostfd,
+ size_t *vhostfdSize)
+{
+ size_t i;
+
+ for (i = 0; i < *vhostfdSize; i++) {
+ vhostfd[i] = open("/dev/vhost-scsi", O_RDWR);
+
+ if (vhostfd[i] < 0) {
+ virReportSystemError(errno, "%s",
+ _("vhost-scsi was requested for an interface,
"
+ "but is unavailable"));
+ goto error;
+ }
+ }
+
+ return 0;
+
+ error:
+ while (i--)
+ VIR_FORCE_CLOSE(vhostfd[i]);
+
+ return -1;
+}
+
char *
virSCSIDeviceGetSgName(const char *sysfs_prefix,
const char *adapter,
diff --git a/src/util/virscsi.h b/src/util/virscsi.h
index df40d7f..cb37da8 100644
--- a/src/util/virscsi.h
+++ b/src/util/virscsi.h
@@ -33,6 +33,7 @@ typedef virSCSIDevice *virSCSIDevicePtr;
typedef struct _virSCSIDeviceList virSCSIDeviceList;
typedef virSCSIDeviceList *virSCSIDeviceListPtr;
+int virSCSIOpenVhost(int *vhostfd, size_t *vhostfdSize);
char *virSCSIDeviceGetSgName(const char *sysfs_prefix,
const char *adapter,
unsigned int bus,
--
1.9.1