--- /dev/null
+From 32b2397c1e56f33b0b1881def965bb89bd12f448 Mon Sep 17 00:00:00 2001
+From: sumiyawang <sumiyawang@tencent.com>
+Date: Sun, 22 Aug 2021 19:49:09 +0800
+Subject: libnvdimm/pmem: Fix crash triggered when I/O in-flight during unbind
+
+From: sumiyawang <sumiyawang@tencent.com>
+
+commit 32b2397c1e56f33b0b1881def965bb89bd12f448 upstream.
+
+There is a use after free crash when the pmem driver tears down its
+mapping while I/O is still inbound.
+
+This is triggered by driver unbind, "ndctl destroy-namespace", while I/O
+is in flight.
+
+Fix the sequence of blk_cleanup_queue() vs memunmap().
+
+The crash signature is of the form:
+
+ BUG: unable to handle page fault for address: ffffc90080200000
+ CPU: 36 PID: 9606 Comm: systemd-udevd
+ Call Trace:
+ ? pmem_do_bvec+0xf9/0x3a0
+ ? xas_alloc+0x55/0xd0
+ pmem_rw_page+0x4b/0x80
+ bdev_read_page+0x86/0xb0
+ do_mpage_readpage+0x5d4/0x7a0
+ ? lru_cache_add+0xe/0x10
+ mpage_readpages+0xf9/0x1c0
+ ? bd_link_disk_holder+0x1a0/0x1a0
+ blkdev_readpages+0x1d/0x20
+ read_pages+0x67/0x1a0
+
+ ndctl Call Trace in vmcore:
+ PID: 23473 TASK: ffff88c4fbbe8000 CPU: 1 COMMAND: "ndctl"
+ __schedule
+ schedule
+ blk_mq_freeze_queue_wait
+ blk_freeze_queue
+ blk_cleanup_queue
+ pmem_release_queue
+ devm_action_release
+ release_nodes
+ devres_release_all
+ device_release_driver_internal
+ device_driver_detach
+ unbind_store
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: sumiyawang <sumiyawang@tencent.com>
+Reviewed-by: yongduan <yongduan@tencent.com>
+Link: https://lore.kernel.org/r/1629632949-14749-1-git-send-email-sumiyawang@tencent.com
+Fixes: 50f44ee7248a ("mm/devm_memremap_pages: fix final page put race")
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+[tyhicks: Minor contextual change in pmem_attach_disk() due to the
+ transition to 'struct range' not yet taking place. Preserve the
+ memcpy() call rather than initializing the range struct. That change
+ was introduced in v5.10 with commit a4574f63edc6 ("mm/memremap_pages:
+ convert to 'struct range'")]
+Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/nvdimm/pmem.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvdimm/pmem.c
++++ b/drivers/nvdimm/pmem.c
+@@ -423,11 +423,11 @@ static int pmem_attach_disk(struct devic
+ pmem->pfn_flags |= PFN_MAP;
+ memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
+ } else {
++ addr = devm_memremap(dev, pmem->phys_addr,
++ pmem->size, ARCH_MEMREMAP_PMEM);
+ if (devm_add_action_or_reset(dev, pmem_release_queue,
+ &pmem->pgmap))
+ return -ENOMEM;
+- addr = devm_memremap(dev, pmem->phys_addr,
+- pmem->size, ARCH_MEMREMAP_PMEM);
+ memcpy(&bb_res, &nsio->res, sizeof(bb_res));
+ }
+
--- /dev/null
+From 9885440b16b8fc1dd7275800fd28f56a92f60896 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Wed, 13 May 2020 17:38:59 -0500
+Subject: PCI: Fix pci_host_bridge struct device release/free handling
+
+From: Rob Herring <robh@kernel.org>
+
+commit 9885440b16b8fc1dd7275800fd28f56a92f60896 upstream.
+
+The PCI code has several paths where the struct pci_host_bridge is freed
+directly. This is wrong because it contains a struct device which is
+refcounted and should be freed using put_device(). This can result in
+use-after-free errors. I think this problem has existed since 2012 with
+commit 7b5436635800 ("PCI: add generic device into pci_host_bridge
+struct"). It generally hasn't mattered as most host bridge drivers are
+still built-in and can't unbind.
+
+The problem is a struct device should never be freed directly once
+device_initialize() is called and a ref is held, but that doesn't happen
+until pci_register_host_bridge(). There's then a window between allocating
+the host bridge and pci_register_host_bridge() where kfree should be used.
+This is fragile and requires callers to do the right thing. To fix this, we
+need to split device_register() into device_initialize() and device_add()
+calls, so that the host bridge struct is always freed by using a
+put_device().
+
+devm_pci_alloc_host_bridge() is using devm_kzalloc() to allocate struct
+pci_host_bridge which will be freed directly. Instead, we can use a custom
+devres action to call put_device().
+
+Link: https://lore.kernel.org/r/20200513223859.11295-2-robh@kernel.org
+Reported-by: Anders Roxell <anders.roxell@linaro.org>
+Tested-by: Anders Roxell <anders.roxell@linaro.org>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+[tyhicks: Minor contextual change in pci_init_host_bridge() due to the
+ lack of a native_dpc member in the pci_host_bridge struct. It was added
+ in v5.7 with commit ac1c8e35a326 ("PCI/DPC: Add Error Disconnect
+ Recover (EDR) support")]
+Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/probe.c | 36 +++++++++++++++++++-----------------
+ drivers/pci/remove.c | 2 +-
+ 2 files changed, 20 insertions(+), 18 deletions(-)
+
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -564,7 +564,7 @@ static struct pci_bus *pci_alloc_bus(str
+ return b;
+ }
+
+-static void devm_pci_release_host_bridge_dev(struct device *dev)
++static void pci_release_host_bridge_dev(struct device *dev)
+ {
+ struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
+
+@@ -573,12 +573,7 @@ static void devm_pci_release_host_bridge
+
+ pci_free_resource_list(&bridge->windows);
+ pci_free_resource_list(&bridge->dma_ranges);
+-}
+-
+-static void pci_release_host_bridge_dev(struct device *dev)
+-{
+- devm_pci_release_host_bridge_dev(dev);
+- kfree(to_pci_host_bridge(dev));
++ kfree(bridge);
+ }
+
+ static void pci_init_host_bridge(struct pci_host_bridge *bridge)
+@@ -597,6 +592,8 @@ static void pci_init_host_bridge(struct
+ bridge->native_shpc_hotplug = 1;
+ bridge->native_pme = 1;
+ bridge->native_ltr = 1;
++
++ device_initialize(&bridge->dev);
+ }
+
+ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
+@@ -614,17 +611,25 @@ struct pci_host_bridge *pci_alloc_host_b
+ }
+ EXPORT_SYMBOL(pci_alloc_host_bridge);
+
++static void devm_pci_alloc_host_bridge_release(void *data)
++{
++ pci_free_host_bridge(data);
++}
++
+ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
+ size_t priv)
+ {
++ int ret;
+ struct pci_host_bridge *bridge;
+
+- bridge = devm_kzalloc(dev, sizeof(*bridge) + priv, GFP_KERNEL);
++ bridge = pci_alloc_host_bridge(priv);
+ if (!bridge)
+ return NULL;
+
+- pci_init_host_bridge(bridge);
+- bridge->dev.release = devm_pci_release_host_bridge_dev;
++ ret = devm_add_action_or_reset(dev, devm_pci_alloc_host_bridge_release,
++ bridge);
++ if (ret)
++ return NULL;
+
+ return bridge;
+ }
+@@ -632,10 +637,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge
+
+ void pci_free_host_bridge(struct pci_host_bridge *bridge)
+ {
+- pci_free_resource_list(&bridge->windows);
+- pci_free_resource_list(&bridge->dma_ranges);
+-
+- kfree(bridge);
++ put_device(&bridge->dev);
+ }
+ EXPORT_SYMBOL(pci_free_host_bridge);
+
+@@ -866,7 +868,7 @@ static int pci_register_host_bridge(stru
+ if (err)
+ goto free;
+
+- err = device_register(&bridge->dev);
++ err = device_add(&bridge->dev);
+ if (err) {
+ put_device(&bridge->dev);
+ goto free;
+@@ -933,7 +935,7 @@ static int pci_register_host_bridge(stru
+
+ unregister:
+ put_device(&bridge->dev);
+- device_unregister(&bridge->dev);
++ device_del(&bridge->dev);
+
+ free:
+ kfree(bus);
+@@ -2945,7 +2947,7 @@ struct pci_bus *pci_create_root_bus(stru
+ return bridge->bus;
+
+ err_out:
+- kfree(bridge);
++ put_device(&bridge->dev);
+ return NULL;
+ }
+ EXPORT_SYMBOL_GPL(pci_create_root_bus);
+--- a/drivers/pci/remove.c
++++ b/drivers/pci/remove.c
+@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus
+ host_bridge->bus = NULL;
+
+ /* remove the host bridge */
+- device_unregister(&host_bridge->dev);
++ device_del(&host_bridge->dev);
+ }
+ EXPORT_SYMBOL_GPL(pci_remove_root_bus);