From: Nicholas Bellinger <nab(a)linux-iscsi.org>
This patch adds support for device_add hotplug for vhost-scsi-pci
against QEMU >= v1.5.x code.
This includes:
- Add qemuOpenVhostSCSI() to open fds to /dev/vhost-scsi character
device.
- Changes to qemuBuildControllerDevStr() for adding 'vhostfd='
parameters to device_add.
- Add qemuMonitorAddControllerVhost() that is specific to
VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI
- Update qemuDomainAttachControllerDevice() to setup vhostfd
fd + name arrays, and invoke qemuOpenVhostSCSI().
- Update qemuDomainAttachControllerDevice() to invoke
qemuMonitorAddControllerVhost() -> qemuMonitorSendFileHandle() ->
qemuMonitorAddDevice() in order to pass the pre-opened vhostfd.
This code has been tested using openstack nova volume-attach, using
a Juno v2 development head from 07192014.
Signed-off-by: Nicholas Bellinger <nab(a)linux-iscsi.org>
Signed-off-by: Mike Perez <thingee(a)gmail.com>
---
src/qemu/qemu_command.c | 56 ++++++++++++++++++++++++++++++++++++++++++++---
src/qemu/qemu_command.h | 8 ++++++-
src/qemu/qemu_hotplug.c | 47 +++++++++++++++++++++++++++++++++++++--
src/qemu/qemu_monitor.c | 24 ++++++++++++++++++++
src/qemu/qemu_monitor.h | 4 ++++
5 files changed, 133 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 43c0e1c..1e987f9 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -678,6 +678,38 @@ static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk)
return 0;
}
+int
+qemuOpenVhostSCSI(virDomainControllerDefPtr controller,
+ int *vhostfd,
+ int *vhostfdSize)
+{
+ size_t i;
+
+ if (controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI) {
+ *vhostfdSize = 0;
+ return 0;
+ }
+
+ for (i = 0; i < *vhostfdSize; i++) {
+ vhostfd[i] = open("/dev/vhost-scsi", O_RDWR);
+
+ if (vhostfd[i] < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%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;
+}
+
static int
qemuSetSCSIControllerModel(virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
@@ -4153,10 +4185,13 @@ char *
qemuBuildControllerDevStr(virDomainDefPtr domainDef,
virDomainControllerDefPtr def,
virQEMUCapsPtr qemuCaps,
- int *nusbcontroller)
+ int *nusbcontroller,
+ char **vhostfd,
+ int vhostfdSize)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
int model;
+ size_t i;
if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
(def->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI ||
@@ -4328,6 +4363,19 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef,
if (def->wwpn)
virBufferAsprintf(&buf, ",wwpn=%s", def->wwpn);
+ if (vhostfdSize) {
+ if (vhostfdSize == 1) {
+ virBufferAsprintf(&buf, ",vhostfd=%s", vhostfd[0]);
+ } else {
+ virBufferAddLit(&buf, ",vhostfds=");
+ for (i = 0; i < vhostfdSize; i++) {
+ if (i)
+ virBufferAddChar(&buf, ':');
+ virBufferAdd(&buf, vhostfd[i], -1);
+ }
+ }
+ }
+
if (qemuBuildDeviceAddressStr(&buf, domainDef, &def->info, qemuCaps) <
0)
goto error;
@@ -7843,7 +7891,8 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandAddArg(cmd, "-device");
if (!(devstr = qemuBuildControllerDevStr(def, cont,
- qemuCaps, NULL)))
+ qemuCaps, NULL,
+ NULL, 0)))
goto error;
virCommandAddArg(cmd, devstr);
@@ -7867,7 +7916,8 @@ qemuBuildCommandLine(virConnectPtr conn,
char *devstr;
if (!(devstr = qemuBuildControllerDevStr(def, cont, qemuCaps,
- &usbcontroller)))
+ &usbcontroller, NULL,
+ 0)))
goto error;
virCommandAddArg(cmd, devstr);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index cf51056..b0651ff 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -114,6 +114,10 @@ char * qemuBuildNicDevStr(virDomainDefPtr def,
char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
virQEMUCapsPtr qemuCaps);
+int qemuOpenVhostSCSI(virDomainControllerDefPtr controller,
+ int *vhostfd,
+ int *vhostfdSize);
+
/* Both legacy & current support */
char *qemuBuildDriveStr(virConnectPtr conn,
virDomainDiskDefPtr disk,
@@ -134,7 +138,9 @@ char * qemuBuildFSDevStr(virDomainDefPtr domainDef,
char * qemuBuildControllerDevStr(virDomainDefPtr domainDef,
virDomainControllerDefPtr def,
virQEMUCapsPtr qemuCaps,
- int *nusbcontroller);
+ int *nusbcontroller,
+ char **vhostfd,
+ int vhostfdSize);
char * qemuBuildWatchdogDevStr(virDomainDefPtr domainDef,
virDomainWatchdogDefPtr dev,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 1fc28b8..4cdac56 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -360,9 +360,13 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainControllerDefPtr controller)
{
+ size_t i;
int ret = -1;
const char* type = virDomainControllerTypeToString(controller->type);
char *devstr = NULL;
+ char **vhostfdName = NULL;
+ int *vhostfd = NULL;
+ int vhostfdSize = 0;
qemuDomainObjPrivatePtr priv = vm->privateData;
bool releaseaddr = false;
@@ -403,7 +407,30 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
goto cleanup;
}
- if (!(devstr = qemuBuildControllerDevStr(vm->def, controller,
priv->qemuCaps, NULL))) {
+ if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI) {
+ /* FIXME: Get total number of virtio-scsi queues */
+ vhostfdSize = 1;
+
+ if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
+ goto cleanup;
+
+ memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
+
+ if (VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
+ goto cleanup;
+
+ if (qemuOpenVhostSCSI(controller, vhostfd, &vhostfdSize) < 0)
+ goto cleanup;
+
+ for (i = 0; i < vhostfdSize; i++) {
+ if (virAsprintf(&vhostfdName[i], "vhostfd-%s%zu",
+ controller->info.alias, i) < 0)
+ goto cleanup;
+ }
+ }
+
+ if (!(devstr = qemuBuildControllerDevStr(vm->def, controller,
priv->qemuCaps,
+ NULL, vhostfdName, vhostfdSize))) {
goto cleanup;
}
}
@@ -413,7 +440,12 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
- ret = qemuMonitorAddDevice(priv->mon, devstr);
+ if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI) {
+ ret = qemuMonitorAddControllerVhost(priv->mon, devstr,
+ vhostfd, vhostfdName, vhostfdSize);
+ } else {
+ ret = qemuMonitorAddDevice(priv->mon, devstr);
+ }
} else {
ret = qemuMonitorAttachPCIDiskController(priv->mon,
type,
@@ -421,6 +453,9 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
}
qemuDomainObjExitMonitor(driver, vm);
+ for (i = 0; i < vhostfdSize; i++)
+ VIR_FORCE_CLOSE(vhostfd[i]);
+
if (ret == 0) {
if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -431,6 +466,14 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
if (ret != 0 && releaseaddr)
qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL);
+ for (i = 0; vhostfd && i < vhostfdSize; i++) {
+ VIR_FORCE_CLOSE(vhostfd[i]);
+ if (vhostfdName)
+ VIR_FREE(vhostfdName[i]);
+ }
+ VIR_FREE(vhostfd);
+ VIR_FREE(vhostfdName);
+
VIR_FREE(devstr);
return ret;
}
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db3dd73..3e67c85 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3052,6 +3052,30 @@ int qemuMonitorAddDevice(qemuMonitorPtr mon,
return qemuMonitorAddDeviceWithFd(mon, devicestr, -1, NULL);
}
+int qemuMonitorAddControllerVhost(qemuMonitorPtr mon,
+ const char *devicestr,
+ int *vhostfd, char **vhostfdName, int vhostfdSize)
+{
+ size_t i = 0;
+
+ for (i = 0; i < vhostfdSize; i++) {
+ if (qemuMonitorSendFileHandle(mon, vhostfdName[i], vhostfd[i]) < 0)
+ goto cleanup;
+ }
+
+ if (qemuMonitorAddDevice(mon, devicestr) < 0)
+ goto cleanup;
+
+ return 0;
+
+ cleanup:
+ while (i--) {
+ if (qemuMonitorCloseFileHandle(mon, vhostfdName[i]) < 0)
+ VIR_WARN("failed to close device handle '%s'",
vhostfdName[i]);
+ }
+ return -1;
+}
+
int qemuMonitorAddDrive(qemuMonitorPtr mon,
const char *drivestr)
{
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 8a23267..8fe21a0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -620,6 +620,10 @@ int qemuMonitorAddDeviceWithFd(qemuMonitorPtr mon,
int fd,
const char *fdname);
+int qemuMonitorAddControllerVhost(qemuMonitorPtr mon,
+ const char *devicestr,
+ int *vhostfd, char **vhostfdName, int vhostfdSize);
+
int qemuMonitorDelDevice(qemuMonitorPtr mon,
const char *devalias);
--
1.7.9.5