From 2d3cf60328c138f7a8fd5905eb345d5f48227ff8 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Tue, 3 Mar 2020 22:22:14 -0500 Subject: [PATCH] qemu: hook up pcie-root-port hotplug='off' option If a pcie-root-port or pcie-downstream-port has hotplug='off' in its subelement, and if the qemu binary supports the hotplug=false option, then it will be added to the commandline for the pcie controller. This controller will then not allow any hotplug/unplug of devices while the guest is running (and the hotplug capability won't be advertised to the guest OS, so the guest OS also won't present unplugging of PCI devices as an option). For any PCI controllers other than pcie-downstream-port and pcie-root-port, of for qemu binaries that don't support the hotplug commandline option, an error will be logged during validation. Signed-off-by: Laine Stump Reviewed-by: Michal Privoznik --- src/qemu/qemu_command.c | 4 ++ src/qemu/qemu_validate.c | 31 +++++++++++++ ...cie-root-port-nohotplug.x86_64-latest.args | 46 +++++++++++++++++++ tests/qemuxml2argvtest.c | 1 + 4 files changed, 82 insertions(+) create mode 100644 tests/qemuxml2argvdata/pcie-root-port-nohotplug.x86_64-latest.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8c6c95a5b9..95402fc4ff 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3026,6 +3026,10 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s", modelName, pciopts->port, pciopts->chassis, def->info.alias); + if (pciopts->hotplug != VIR_TRISTATE_SWITCH_ABSENT) { + virBufferAsprintf(&buf, ",hotplug=%s", + virTristateSwitchTypeToString(pciopts->hotplug)); + } break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: virBufferAsprintf(&buf, "%s,index=%d,id=%s", diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 149b9e738e..971e4a945a 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -2637,6 +2637,37 @@ qemuValidateDomainDeviceDefControllerPCI(const virDomainControllerDef *cont, virReportEnumRangeError(virDomainControllerModelPCI, cont->model); } + /* hotplug */ + if (pciopts->hotplug != VIR_TRISTATE_SWITCH_ABSENT) { + switch ((virDomainControllerModelPCI) cont->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIE_ROOT_PORT_HOTPLUG)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("setting the hotplug property on a '%s' device is not supported by this QEMU binary"), + modelName); + return -1; + } + break; + + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE: + virReportControllerInvalidOption(cont, model, modelName, "hotplug"); + return -1; + + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: + default: + virReportEnumRangeError(virDomainControllerModelPCI, cont->model); + } + } + /* QEMU device availability */ if (cap < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/tests/qemuxml2argvdata/pcie-root-port-nohotplug.x86_64-latest.args b/tests/qemuxml2argvdata/pcie-root-port-nohotplug.x86_64-latest.args new file mode 100644 index 0000000000..0f81b31ad9 --- /dev/null +++ b/tests/qemuxml2argvdata/pcie-root-port-nohotplug.x86_64-latest.args @@ -0,0 +1,46 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-guest \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-guest/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-guest/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-guest/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name guest=guest,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,\ +file=/tmp/lib/domain--1-guest/master-key.aes \ +-machine q35,accel=tcg,usb=off,dump-guest-core=off \ +-cpu qemu64 \ +-m 2048 \ +-overcommit mem-lock=off \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-device pcie-root-port,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\ +addr=0x1 \ +-device pcie-root-port,port=0x9,chassis=2,id=pci.2,hotplug=off,bus=pcie.0,\ +addr=0x1.0x1 \ +-device ioh3420,port=0xa,chassis=3,id=pci.3,hotplug=off,bus=pcie.0,\ +addr=0x1.0x2 \ +-device x3130-upstream,id=pci.4,bus=pci.1,addr=0x0 \ +-device xio3130-downstream,port=0x0,chassis=5,id=pci.5,hotplug=off,bus=pci.4,\ +addr=0x0 \ +-device xio3130-downstream,port=0x1,chassis=6,id=pci.6,hotplug=on,bus=pci.4,\ +addr=0x1 \ +-device xio3130-downstream,port=0x2,chassis=7,id=pci.7,bus=pci.4,addr=0x2 \ +-device xio3130-downstream,port=0x27,chassis=30,id=pci.8,bus=pci.4,addr=0x3 \ +-device qemu-xhci,id=usb,bus=pci.2,addr=0x0 \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\ +resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 405227fdf6..66472a5ee5 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -2435,6 +2435,7 @@ mymain(void) QEMU_CAPS_DEVICE_IOH3420); DO_TEST("pcie-root-port-model-ioh3420", QEMU_CAPS_DEVICE_IOH3420); + DO_TEST_CAPS_LATEST("pcie-root-port-nohotplug"); DO_TEST("autoindex", QEMU_CAPS_DEVICE_PCI_BRIDGE,