--- /dev/null
+From a46044a92add6a400f4dada7b943b30221f7cc80 Mon Sep 17 00:00:00 2001
+From: Niklas Schnelle <schnelle@linux.ibm.com>
+Date: Wed, 22 Sep 2021 15:55:12 +0200
+Subject: s390/pci: fix zpci_zdev_put() on reserve
+
+From: Niklas Schnelle <schnelle@linux.ibm.com>
+
+commit a46044a92add6a400f4dada7b943b30221f7cc80 upstream.
+
+Since commit 2a671f77ee49 ("s390/pci: fix use after free of zpci_dev")
+the reference count of a zpci_dev is incremented between
+pcibios_add_device() and pcibios_release_device() which was supposed to
+prevent the zpci_dev from being freed while the common PCI code has
+access to it. It was missed however that the handling of zPCI
+availability events assumed that once zpci_zdev_put() was called no
+later availability event would still see the device. With the previously
+mentioned commit however this assumption no longer holds and we must
+make sure that we only drop the initial long-lived reference the zPCI
+subsystem holds exactly once.
+
+Do so by introducing a zpci_device_reserved() function that handles when
+a device is reserved. Here we make sure the zpci_dev will not be
+considered for further events by removing it from the zpci_list.
+
+This also means that the device actually stays in the
+ZPCI_FN_STATE_RESERVED state between the time we know it has been
+reserved and the final reference going away. We thus need to consider it
+a real state instead of just a conceptual state after the removal. The
+final cleanup of PCI resources, removal from zbus, and destruction of
+the IOMMU stays in zpci_release_device() to make sure holders of the
+reference do see valid data until the release.
+
+Fixes: 2a671f77ee49 ("s390/pci: fix use after free of zpci_dev")
+Cc: stable@vger.kernel.org
+Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/s390/include/asm/pci.h | 3 ++
+ arch/s390/pci/pci.c | 45 ++++++++++++++++++++++++++++++++-----
+ arch/s390/pci/pci_event.c | 4 +--
+ drivers/pci/hotplug/s390_pci_hpc.c | 9 -------
+ 4 files changed, 46 insertions(+), 15 deletions(-)
+
+--- a/arch/s390/include/asm/pci.h
++++ b/arch/s390/include/asm/pci.h
+@@ -205,6 +205,9 @@ int zpci_create_device(u32 fid, u32 fh,
+ void zpci_remove_device(struct zpci_dev *zdev, bool set_error);
+ int zpci_enable_device(struct zpci_dev *);
+ int zpci_disable_device(struct zpci_dev *);
++void zpci_device_reserved(struct zpci_dev *zdev);
++bool zpci_is_device_configured(struct zpci_dev *zdev);
++
+ int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
+ int zpci_unregister_ioat(struct zpci_dev *, u8);
+ void zpci_remove_reserved_devices(void);
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -92,7 +92,7 @@ void zpci_remove_reserved_devices(void)
+ spin_unlock(&zpci_list_lock);
+
+ list_for_each_entry_safe(zdev, tmp, &remove, entry)
+- zpci_zdev_put(zdev);
++ zpci_device_reserved(zdev);
+ }
+
+ int pci_domain_nr(struct pci_bus *bus)
+@@ -787,6 +787,39 @@ error:
+ return rc;
+ }
+
++bool zpci_is_device_configured(struct zpci_dev *zdev)
++{
++ enum zpci_state state = zdev->state;
++
++ return state != ZPCI_FN_STATE_RESERVED &&
++ state != ZPCI_FN_STATE_STANDBY;
++}
++
++/**
++ * zpci_device_reserved() - Mark device as resverved
++ * @zdev: the zpci_dev that was reserved
++ *
++ * Handle the case that a given zPCI function was reserved by another system.
++ * After a call to this function the zpci_dev can not be found via
++ * get_zdev_by_fid() anymore but may still be accessible via existing
++ * references though it will not be functional anymore.
++ */
++void zpci_device_reserved(struct zpci_dev *zdev)
++{
++ if (zdev->has_hp_slot)
++ zpci_exit_slot(zdev);
++ /*
++ * Remove device from zpci_list as it is going away. This also
++ * makes sure we ignore subsequent zPCI events for this device.
++ */
++ spin_lock(&zpci_list_lock);
++ list_del(&zdev->entry);
++ spin_unlock(&zpci_list_lock);
++ zdev->state = ZPCI_FN_STATE_RESERVED;
++ zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
++ zpci_zdev_put(zdev);
++}
++
+ void zpci_release_device(struct kref *kref)
+ {
+ struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
+@@ -802,6 +835,12 @@ void zpci_release_device(struct kref *kr
+ case ZPCI_FN_STATE_STANDBY:
+ if (zdev->has_hp_slot)
+ zpci_exit_slot(zdev);
++ spin_lock(&zpci_list_lock);
++ list_del(&zdev->entry);
++ spin_unlock(&zpci_list_lock);
++ zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
++ fallthrough;
++ case ZPCI_FN_STATE_RESERVED:
+ if (zdev->has_resources)
+ zpci_cleanup_bus_resources(zdev);
+ zpci_bus_device_unregister(zdev);
+@@ -810,10 +849,6 @@ void zpci_release_device(struct kref *kr
+ default:
+ break;
+ }
+-
+- spin_lock(&zpci_list_lock);
+- list_del(&zdev->entry);
+- spin_unlock(&zpci_list_lock);
+ zpci_dbg(3, "rem fid:%x\n", zdev->fid);
+ kfree(zdev);
+ }
+--- a/arch/s390/pci/pci_event.c
++++ b/arch/s390/pci/pci_event.c
+@@ -146,7 +146,7 @@ static void __zpci_event_availability(st
+ zdev->state = ZPCI_FN_STATE_STANDBY;
+ if (!clp_get_state(ccdf->fid, &state) &&
+ state == ZPCI_FN_STATE_RESERVED) {
+- zpci_zdev_put(zdev);
++ zpci_device_reserved(zdev);
+ }
+ break;
+ case 0x0306: /* 0x308 or 0x302 for multiple devices */
+@@ -156,7 +156,7 @@ static void __zpci_event_availability(st
+ case 0x0308: /* Standby -> Reserved */
+ if (!zdev)
+ break;
+- zpci_zdev_put(zdev);
++ zpci_device_reserved(zdev);
+ break;
+ default:
+ break;
+--- a/drivers/pci/hotplug/s390_pci_hpc.c
++++ b/drivers/pci/hotplug/s390_pci_hpc.c
+@@ -109,14 +109,7 @@ static int get_power_status(struct hotpl
+ struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
+ hotplug_slot);
+
+- switch (zdev->state) {
+- case ZPCI_FN_STATE_STANDBY:
+- *value = 0;
+- break;
+- default:
+- *value = 1;
+- break;
+- }
++ *value = zpci_is_device_configured(zdev) ? 1 : 0;
+ return 0;
+ }
+