On 09/06/2016 08:58 AM, Eric Farman wrote:
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@xxxxxxxxxxxxxxxxxx>
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_command.h | 6 ++++
src/util/virscsi.c | 26 ++++++++++++++++
src/util/virscsi.h | 1 +
5 files changed, 114 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d62c74c..22fe14d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2265,6 +2265,7 @@ virSCSIDeviceListNew;
virSCSIDeviceListSteal;
virSCSIDeviceNew;
virSCSIDeviceSetUsedBy;
+virSCSIOpenVhost;
# util/virseclabel.h
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 982c33c..479dde2 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4711,6 +4711,52 @@ qemuBuildSCSIiSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
}
char *
+qemuBuildHostHostdevDevStr(const virDomainDef *def,
+ virDomainHostdevDefPtr dev,
+ virQEMUCapsPtr qemuCaps,
+ char *vhostfdName,
+ size_t vhostfdSize)
+{
+ 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);
This is where id add the "naa." prefix, e.g wwpn=naa.%s" - with a
somewhat healthy comment behind it as to why it's being used.
+
+ if (vhostfdSize == 1) {
+ virBufferAsprintf(&buf, ",vhostfd=%s", vhostfdName);
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("QEMU supports a single vhost-scsi file descriptor"));
+ goto cleanup;
+ }
+
+ virBufferAsprintf(&buf, ",id=%s", dev->info->alias);
+
+ if (qemuBuildDeviceAddressStr(&buf, def, dev->info, qemuCaps) < 0)
+ goto cleanup;
I think this is what I would think auditing (during hotplug of course)
would end up using as the address rather than what will happen in patch
1 resulting in "?" being displayed.
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ return virBufferContentAndReset(&buf);
+
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+char *
qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -5156,6 +5202,40 @@ 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)) {
I'm conflicted if we should check QEMU_CAPS_DEVICE_VHOST_SCSI here as
well... I know it's checked later, but we open vhost-scsi which I
assume wouldn't exist if the cap wasn't there.
Of course I see in hotplug things have to be a little different in order
to add that fd and name via monitor rather than command.
+ if (hostdev->source.subsys.u.host.protocol == VIR_DOMAIN_HOSTDEV_HOST_PROTOCOL_TYPE_VHOST) {
80 cols for the line
+ char *vhostfdName = NULL;
+ int vhostfd = -1;
+ size_t vhostfdSize = 1;
+
+ if (virSCSIOpenVhost(&vhostfd, &vhostfdSize) < 0)
+ return -1;
+
+ if (virAsprintf(&vhostfdName, "%d", vhostfd) < 0) {
+ VIR_FORCE_CLOSE(vhostfd);
+ return -1;
+ }
+
+ virCommandPassFD(cmd, vhostfd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
80 cols for the line.
+
+ virCommandAddArg(cmd, "-device");
+ if (!(devstr = qemuBuildHostHostdevDevStr(def, hostdev, qemuCaps, vhostfdName, vhostfdSize)))
This is a really long line - try to keep at 80 cols.
+ return -1;
We'd leak vhostfdName on failure (I think the vhostfd will be reaped by
Command cleanup.
+ virCommandAddArg(cmd, devstr);
+
+ VIR_FREE(vhostfdName);
+ VIR_FREE(devstr);
+ }
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("SCSI passthrough is not supported by this version of qemu"));
+ return -1;
+ }
+ }
}
return 0;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 9b9ccb6..78179de 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -158,6 +158,12 @@ char *qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev);
char *qemuBuildSCSIHostdevDevStr(const virDomainDef *def,
virDomainHostdevDefPtr dev,
virQEMUCapsPtr qemuCaps);
+char *
+qemuBuildHostHostdevDevStr(const virDomainDef *def,
+ virDomainHostdevDefPtr dev,
+ virQEMUCapsPtr qemuCaps,
+ char *vhostfdName,
+ size_t vhostfdSize);
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)
Well this is dangerous... I can pass "any" value value here and really
cause some damage. Why the need for a loop?