diff --git a/libvirt.changes b/libvirt.changes index 3c8b8f7..1c5e4a7 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Fri Jul 15 14:57:40 UTC 2016 - jfehlig@suse.com + +- BuildRequires: use librbd-devel instead of ceph-devel +- Enable rbd support for aarch64 + bsc#979473 + +------------------------------------------------------------------- +Thu Jul 14 22:39:08 UTC 2016 - jfehlig@suse.com + +- Use driver_override sysfs interface for binding/unbinding + PCI stub drivers + pci-simplify-stub.patch, pci-use-driver-override-sysfs.patch + bsc#986718 + ------------------------------------------------------------------- Tue Jul 12 19:57:40 UTC 2016 - jfehlig@suse.com diff --git a/libvirt.spec b/libvirt.spec index b200649..fcb67c1 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -102,11 +102,30 @@ %define with_phyp 1 %endif -# For now, only enable rbd storage backend on x86_64 SLE -%if %{with_sle_build} - %ifarch x86_64 - %define with_storage_rbd 1 - %endif +# rbd enablement is a bit tricky. For x86_64 +%ifarch x86_64 +# enable on anything newer than 1320, or SLE12 family newer than 120100 +# use librbd-devel as build dependency +%if 0%{?suse_version} > 1320 || ( 0%{?suse_version} == 1315 && ( 0%{?sle_version} > 120100 ) ) +%define with_storage_rbd 1 +%define with_rbd_lib librbd-devel +%endif +# enable for SLE12 family <= 120100 (SLE12ga/sp1, Leap 42.1) +# use ceph-devel as build dependency +%if 0%{?suse_version} == 1315 && 0%{?sle_version} <= 120100 +%define with_storage_rbd 1 +%define with_rbd_lib ceph-devel +%endif +%endif + +# For arm +%ifarch aarch64 +# enable on anything newer than 1320, or SLE12 family newer than 120100 +# use librbd-devel as build dependency +%if 0%{?suse_version} > 1320 || ( 0%{?is_opensuse} == 0 && 0%{?sle_version} > 120100 ) +%define with_storage_rbd 1 +%define with_rbd_lib librbd-devel +%endif %endif # Support systemd on 12.1 and later @@ -240,7 +259,7 @@ BuildRequires: parted-devel # For Multipath support BuildRequires: device-mapper-devel %if %{with_storage_rbd} -BuildRequires: ceph-devel +BuildRequires: %{with_rbd_lib} %endif %if %{with_numactl} # For QEMU/LXC numa info @@ -282,6 +301,8 @@ Source100: %{name}-rpmlintrc Patch0: c8f08e48-systemd-notify-fix.patch # Patches pending upstream review Patch100: libxl-dom-reset.patch +Patch101: pci-simplify-stub.patch +Patch102: pci-use-driver-override-sysfs.patch # Need to go upstream Patch150: xen-pv-cdrom.patch Patch151: blockcopy-check-dst-identical-device.patch @@ -733,6 +754,8 @@ libvirt plugin for NSS for translating domain names into IP addresses. %setup -q %patch0 -p1 %patch100 -p1 +%patch101 -p1 +%patch102 -p1 %patch150 -p1 %patch151 -p1 %patch152 -p1 diff --git a/pci-simplify-stub.patch b/pci-simplify-stub.patch new file mode 100644 index 0000000..42c03d8 --- /dev/null +++ b/pci-simplify-stub.patch @@ -0,0 +1,118 @@ +commit caba00f00fb18d8ffc388f4fc8b82527ef98d3b0 +Author: Jim Fehlig +Date: Wed Jul 6 14:06:37 2016 -0600 + + virpci: simplify virPCIDeviceBindToStub + + Early in virPCIDeviceBindToStub, there is a check to see if the + stub is already bound to the device, returning success with no + further actions if that is the case. + + The same condition is unnecessarily checked later in the function. + Remove the unneeded checks to simplify the logic a bit. + + Signed-off-by: Jim Fehlig + +Index: libvirt-2.0.0/src/util/virpci.c +=================================================================== +--- libvirt-2.0.0.orig/src/util/virpci.c ++++ libvirt-2.0.0/src/util/virpci.c +@@ -1196,7 +1196,6 @@ static int + virPCIDeviceBindToStub(virPCIDevicePtr dev) + { + int result = -1; +- bool reprobe = false; + char *stubDriverPath = NULL; + char *driverLink = NULL; + char *path = NULL; /* reused for different purposes */ +@@ -1225,10 +1224,16 @@ virPCIDeviceBindToStub(virPCIDevicePtr d + /* The device is already bound to the correct driver */ + VIR_DEBUG("Device %s is already bound to %s", + dev->name, stubDriverName); ++ dev->unbind_from_stub = true; ++ dev->remove_slot = true; + result = 0; + goto cleanup; + } +- reprobe = true; ++ /* ++ * If the device is bound to a driver that is not the stub, we'll ++ * need to reprobe later ++ */ ++ dev->reprobe = true; + } + + /* Add the PCI device ID to the stub's dynamic ID table; +@@ -1249,51 +1254,34 @@ virPCIDeviceBindToStub(virPCIDevicePtr d + goto cleanup; + } + +- /* check whether the device is bound to pci-stub when we write dev->id to +- * ${stubDriver}/new_id. +- */ +- if (virFileLinkPointsTo(driverLink, stubDriverPath)) { +- dev->unbind_from_stub = true; +- dev->remove_slot = true; +- result = 0; ++ if (virPCIDeviceUnbind(dev) < 0) + goto remove_id; +- } + +- if (virPCIDeviceUnbind(dev) < 0) ++ /* Xen's pciback.ko wants you to use new_slot first */ ++ VIR_FREE(path); ++ if (!(path = virPCIDriverFile(stubDriverName, "new_slot"))) + goto remove_id; + +- /* If the device was bound to a driver we'll need to reprobe later */ +- dev->reprobe = reprobe; ++ if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { ++ virReportSystemError(errno, ++ _("Failed to add slot for " ++ "PCI device '%s' to %s"), ++ dev->name, stubDriverName); ++ goto remove_id; ++ } ++ dev->remove_slot = true; + +- /* If the device isn't already bound to pci-stub, try binding it now. +- */ +- if (!virFileLinkPointsTo(driverLink, stubDriverPath)) { +- /* Xen's pciback.ko wants you to use new_slot first */ +- VIR_FREE(path); +- if (!(path = virPCIDriverFile(stubDriverName, "new_slot"))) +- goto remove_id; +- +- if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { +- virReportSystemError(errno, +- _("Failed to add slot for " +- "PCI device '%s' to %s"), +- dev->name, stubDriverName); +- goto remove_id; +- } +- dev->remove_slot = true; ++ VIR_FREE(path); ++ if (!(path = virPCIDriverFile(stubDriverName, "bind"))) ++ goto remove_id; + +- VIR_FREE(path); +- if (!(path = virPCIDriverFile(stubDriverName, "bind"))) +- goto remove_id; +- +- if (virFileWriteStr(path, dev->name, 0) < 0) { +- virReportSystemError(errno, +- _("Failed to bind PCI device '%s' to %s"), +- dev->name, stubDriverName); +- goto remove_id; +- } +- dev->unbind_from_stub = true; ++ if (virFileWriteStr(path, dev->name, 0) < 0) { ++ virReportSystemError(errno, ++ _("Failed to bind PCI device '%s' to %s"), ++ dev->name, stubDriverName); ++ goto remove_id; + } ++ dev->unbind_from_stub = true; + + result = 0; + diff --git a/pci-use-driver-override-sysfs.patch b/pci-use-driver-override-sysfs.patch new file mode 100644 index 0000000..89b9563 --- /dev/null +++ b/pci-use-driver-override-sysfs.patch @@ -0,0 +1,271 @@ +commit 1de627810eaba897705cf32c9f025023e34ce73a +Author: Jim Fehlig +Date: Fri Jul 8 16:25:03 2016 -0600 + + virpci: support driver_override sysfs interface + + Currently, libvirt uses the new_id PCI sysfs interface to bind a PCI + stub driver to a PCI device. The new_id interface is known to be + buggy and racey, hence a more deterministic interface was introduced + in the 3.12 kernel - driver_override. For more details see + + https://www.redhat.com/archives/libvir-list/2016-June/msg02124.html + + This patch changes the stub binding/unbinding code to use the + driver_override interface if present. If not present, the new_id + interface will be used to provide compatibility with older kernels + lacking driver_override. + + Signed-off-by: Jim Fehlig + +Index: libvirt-2.0.0/src/util/virpci.c +=================================================================== +--- libvirt-2.0.0.orig/src/util/virpci.c ++++ libvirt-2.0.0/src/util/virpci.c +@@ -1158,6 +1158,19 @@ virPCIDeviceUnbindFromStub(virPCIDeviceP + + VIR_DEBUG("Reprobing for PCI device %s", dev->name); + ++ /* Remove driver_override if it exists */ ++ VIR_FREE(path); ++ if (!(path = virPCIFile(dev->name, "driver_override"))) ++ goto cleanup; ++ ++ if (virFileExists(path) && virFileWriteStr(path, "\n", 0) < 0) { ++ virReportSystemError(errno, ++ _("Failed to remove stub driver from " ++ "driver_override interface of PCI device '%s'"), ++ dev->name); ++ goto cleanup; ++ } ++ + /* Trigger a re-probe of the device is not in the stub's dynamic + * ID table. If the stub is available, but 'remove_id' isn't + * available, then re-probing would just cause the device to be +@@ -1193,49 +1206,13 @@ virPCIDeviceUnbindFromStub(virPCIDeviceP + + + static int +-virPCIDeviceBindToStub(virPCIDevicePtr dev) ++virPCIDeviceBindToStubWithNewid(virPCIDevicePtr dev, ++ const char *stubDriverName) + { +- int result = -1; +- char *stubDriverPath = NULL; +- char *driverLink = NULL; +- char *path = NULL; /* reused for different purposes */ +- const char *stubDriverName = NULL; ++ int ret = -1; ++ char *path = NULL; + virErrorPtr err = NULL; + +- /* Check the device is configured to use one of the known stub drivers */ +- if (dev->stubDriver == VIR_PCI_STUB_DRIVER_NONE) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("No stub driver configured for PCI device %s"), +- dev->name); +- return -1; +- } else if (!(stubDriverName = virPCIStubDriverTypeToString(dev->stubDriver))) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("Unknown stub driver configured for PCI device %s"), +- dev->name); +- return -1; +- } +- +- if (!(stubDriverPath = virPCIDriverDir(stubDriverName)) || +- !(driverLink = virPCIFile(dev->name, "driver"))) +- goto cleanup; +- +- if (virFileExists(driverLink)) { +- if (virFileLinkPointsTo(driverLink, stubDriverPath)) { +- /* The device is already bound to the correct driver */ +- VIR_DEBUG("Device %s is already bound to %s", +- dev->name, stubDriverName); +- dev->unbind_from_stub = true; +- dev->remove_slot = true; +- result = 0; +- goto cleanup; +- } +- /* +- * If the device is bound to a driver that is not the stub, we'll +- * need to reprobe later +- */ +- dev->reprobe = true; +- } +- + /* Add the PCI device ID to the stub's dynamic ID table; + * this is needed to allow us to bind the device to the stub. + * Note: if the device is not currently bound to any driver, +@@ -1283,7 +1260,7 @@ virPCIDeviceBindToStub(virPCIDevicePtr d + } + dev->unbind_from_stub = true; + +- result = 0; ++ ret = 0; + + remove_id: + err = virSaveLastError(); +@@ -1299,7 +1276,7 @@ virPCIDeviceBindToStub(virPCIDevicePtr d + "cannot be probed again.", dev->id, stubDriverName); + } + dev->reprobe = false; +- result = -1; ++ ret = -1; + goto cleanup; + } + +@@ -1314,10 +1291,142 @@ virPCIDeviceBindToStub(virPCIDevicePtr d + "cannot be probed again.", dev->id, stubDriverName); + } + dev->reprobe = false; +- result = -1; ++ ret = -1; ++ goto cleanup; ++ } ++ ++ cleanup: ++ VIR_FREE(path); ++ ++ if (err) ++ virSetError(err); ++ virFreeError(err); ++ ++ return ret; ++} ++ ++ ++static int ++virPCIDeviceBindToStubWithOverride(virPCIDevicePtr dev, ++ const char *stubDriverName) ++{ ++ int ret = -1; ++ char *path = NULL; ++ ++ /* ++ * Add stub to the device's driver_override, falling back to ++ * adding the device ID to the stub's dynamic ID table. ++ */ ++ if (!(path = virPCIFile(dev->name, "driver_override"))) ++ return -1; ++ ++ if (virFileWriteStr(path, stubDriverName, 0) < 0) { ++ virReportSystemError(errno, ++ _("Failed to add stub driver '%s' to " ++ "driver_override interface of PCI device '%s'"), ++ stubDriverName, dev->name); ++ goto cleanup; ++ } ++ ++ if (virPCIDeviceUnbind(dev) < 0) ++ goto cleanup; ++ ++ /* Xen's pciback.ko wants you to use new_slot first */ ++ VIR_FREE(path); ++ if (!(path = virPCIDriverFile(stubDriverName, "new_slot"))) ++ goto cleanup; ++ ++ if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { ++ virReportSystemError(errno, ++ _("Failed to add slot for " ++ "PCI device '%s' to %s"), ++ dev->name, stubDriverName); ++ goto cleanup; ++ } ++ dev->remove_slot = true; ++ ++ if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) { ++ virReportSystemError(errno, ++ _("Failed to trigger a re-probe for PCI device '%s'"), ++ dev->name); + goto cleanup; + } + ++ /* ++ * Device is now bound to the stub. Set reprobe so it will be re-bound ++ * when unbinding from the stub. ++ */ ++ dev->reprobe = true; ++ dev->unbind_from_stub = true; ++ ++ ret = 0; ++ ++ cleanup: ++ VIR_FREE(path); ++ return ret; ++} ++ ++ ++static int ++virPCIDeviceBindToStub(virPCIDevicePtr dev) ++{ ++ int result = -1; ++ char *stubDriverPath = NULL; ++ char *driverLink = NULL; ++ char *path = NULL; /* reused for different purposes */ ++ const char *stubDriverName = NULL; ++ ++ /* Check the device is configured to use one of the known stub drivers */ ++ if (dev->stubDriver == VIR_PCI_STUB_DRIVER_NONE) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("No stub driver configured for PCI device %s"), ++ dev->name); ++ return -1; ++ } else if (!(stubDriverName = virPCIStubDriverTypeToString(dev->stubDriver))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Unknown stub driver configured for PCI device %s"), ++ dev->name); ++ return -1; ++ } ++ ++ if (!(stubDriverPath = virPCIDriverDir(stubDriverName)) || ++ !(driverLink = virPCIFile(dev->name, "driver"))) ++ goto cleanup; ++ ++ if (virFileExists(driverLink)) { ++ if (virFileLinkPointsTo(driverLink, stubDriverPath)) { ++ /* The device is already bound to the correct driver */ ++ VIR_DEBUG("Device %s is already bound to %s", ++ dev->name, stubDriverName); ++ dev->unbind_from_stub = true; ++ dev->remove_slot = true; ++ result = 0; ++ goto cleanup; ++ } ++ /* ++ * If the device is bound to a driver that is not the stub, we'll ++ * need to reprobe later ++ */ ++ dev->reprobe = true; ++ } ++ ++ /* ++ * Add stub to the device's driver_override, falling back to ++ * adding the device ID to the stub's dynamic ID table. ++ */ ++ if (!(path = virPCIFile(dev->name, "driver_override"))) ++ goto cleanup; ++ ++ if (virFileExists(path)) { ++ if (virPCIDeviceBindToStubWithOverride(dev, stubDriverName) < 0) ++ goto cleanup; ++ } else { ++ if (virPCIDeviceBindToStubWithNewid(dev, stubDriverName) < 0) ++ goto cleanup; ++ } ++ ++ result = 0; ++ + cleanup: + VIR_FREE(stubDriverPath); + VIR_FREE(driverLink); +@@ -1326,10 +1435,6 @@ virPCIDeviceBindToStub(virPCIDevicePtr d + if (result < 0) + virPCIDeviceUnbindFromStub(dev); + +- if (err) +- virSetError(err); +- virFreeError(err); +- + return result; + } +