qemu: Add vhost-scsi string for -device parameter

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>
This commit is contained in:
Eric Farman 2016-11-21 22:58:18 -05:00 committed by John Ferlan
parent 629544be0f
commit 9cc26dc622
6 changed files with 167 additions and 2 deletions

View File

@ -299,6 +299,25 @@ qemuSetupHostSCSIDeviceCgroup(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
return ret;
}
static int
qemuSetupHostSCSIVHostDeviceCgroup(virSCSIVHostDevicePtr 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)
@ -308,9 +327,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;
virDomainHostdevSubsysSCSIVHostPtr hostsrc = &dev->source.subsys.u.scsi_host;
virPCIDevicePtr pci = NULL;
virUSBDevicePtr usb = NULL;
virSCSIDevicePtr scsi = NULL;
virSCSIVHostDevicePtr host = NULL;
char *path = NULL;
/* currently this only does something for PCI devices using vfio
@ -399,6 +420,16 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm,
}
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
if (hostsrc->protocol ==
VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST) {
if (!(host = virSCSIVHostDeviceNew(hostsrc->wwpn)))
goto cleanup;
if (virSCSIVHostDeviceFileIterate(host,
qemuSetupHostSCSIVHostDeviceCgroup,
vm) < 0)
goto cleanup;
}
break;
}
@ -412,6 +443,7 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm,
virPCIDeviceFree(pci);
virUSBDeviceFree(usb);
virSCSIDeviceFree(scsi);
virSCSIVHostDeviceFree(host);
VIR_FREE(path);
return ret;
}

View File

@ -4741,6 +4741,44 @@ qemuBuildSCSIiSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
return source;
}
char *
qemuBuildSCSIVHostHostdevDevStr(const virDomainDef *def,
virDomainHostdevDefPtr dev,
virQEMUCapsPtr qemuCaps,
char *vhostfdName)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virDomainHostdevSubsysSCSIVHostPtr hostsrc = &dev->source.subsys.u.scsi_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,vhostfd=%s,id=%s",
hostsrc->wwpn,
vhostfdName,
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)
{
@ -5221,6 +5259,48 @@ qemuBuildHostdevCommandLine(virCommandPtr cmd,
return -1;
}
}
/* SCSI_host */
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
subsys->type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_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.scsi_host.protocol ==
VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST) {
char *vhostfdName = NULL;
int vhostfd = -1;
if (virSCSIVHostOpenVhostSCSI(&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 = qemuBuildSCSIVHostHostdevDevStr(def,
hostdev,
qemuCaps,
vhostfdName))) {
VIR_FREE(vhostfdName);
VIR_FORCE_CLOSE(vhostfd);
return -1;
}
virCommandAddArg(cmd, devstr);
VIR_FREE(vhostfdName);
VIR_FREE(devstr);
}
}
}
return 0;

View File

@ -164,6 +164,11 @@ char *qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev);
char *qemuBuildSCSIHostdevDevStr(const virDomainDef *def,
virDomainHostdevDefPtr dev,
virQEMUCapsPtr qemuCaps);
char *
qemuBuildSCSIVHostHostdevDevStr(const virDomainDef *def,
virDomainHostdevDefPtr dev,
virQEMUCapsPtr qemuCaps,
char *vhostfdName);
char *qemuBuildRedirdevDevStr(const virDomainDef *def,
virDomainRedirdevDefPtr dev,

View File

@ -312,6 +312,14 @@ 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_SCSI_HOST &&
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)
@ -1594,8 +1602,10 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
for (i = 0; i < def->nhostdevs; i++) {
if (!virDeviceInfoPCIAddressWanted(def->hostdevs[i]->info))
continue;
if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
continue;
if (def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST)
continue;
if (qemuDomainPCIAddressReserveNextSlot(addrs,

View File

@ -292,6 +292,17 @@ qemuHostdevPrepareSCSIDevices(virQEMUDriverPtr driver,
name, hostdevs, nhostdevs);
}
int
qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
{
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
return virHostdevPrepareSCSIVHostDevices(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 (qemuHostdevPrepareSCSIVHostDevices(driver, def->name,
def->hostdevs, def->nhostdevs) < 0)
return -1;
return 0;
}
@ -369,6 +384,18 @@ qemuHostdevReAttachSCSIDevices(virQEMUDriverPtr driver,
name, hostdevs, nhostdevs);
}
void
qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
{
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
virHostdevReAttachSCSIVHostDevices(hostdev_mgr, QEMU_DRIVER_NAME,
name, hostdevs, nhostdevs);
}
void
qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def)
@ -384,4 +411,7 @@ qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
qemuHostdevReAttachSCSIDevices(driver, def->name, def->hostdevs,
def->nhostdevs);
qemuHostdevReAttachSCSIVHostDevices(driver, def->name, def->hostdevs,
def->nhostdevs);
}

View File

@ -55,6 +55,10 @@ int qemuHostdevPrepareSCSIDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
int qemuHostdevPrepareSCSIVHostDevices(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 qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
void qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def);