]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
irqdomain/treewide: Free firmware node after domain removal
authorJon Derrick <jonathan.derrick@intel.com>
Tue, 21 Jul 2020 20:26:09 +0000 (14:26 -0600)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 22 Jul 2020 22:08:52 +0000 (00:08 +0200)
Commit 711419e504eb ("irqdomain: Add the missing assignment of
domain->fwnode for named fwnode") unintentionally caused a dangling pointer
page fault issue on firmware nodes that were freed after IRQ domain
allocation. Commit e3beca48a45b fixed that dangling pointer issue by only
freeing the firmware node after an IRQ domain allocation failure. That fix
no longer frees the firmware node immediately, but leaves the firmware node
allocated after the domain is removed.

The firmware node must be kept around through irq_domain_remove, but should be
freed it afterwards.

Add the missing free operations after domain removal where where appropriate.

Fixes: e3beca48a45b ("irqdomain/treewide: Keep firmware node unconditionally allocated")
Signed-off-by: Jon Derrick <jonathan.derrick@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # drivers/pci
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/1595363169-7157-1-git-send-email-jonathan.derrick@intel.com
arch/mips/pci/pci-xtalk-bridge.c
arch/x86/kernel/apic/io_apic.c
drivers/iommu/intel/irq_remapping.c
drivers/mfd/ioc3.c
drivers/pci/controller/vmd.c

index 5958217861b862e45cc1dfe80bf34c33877f60e0..9b3cc775c55e0581943ce3365307a4a545c91c6c 100644 (file)
@@ -728,6 +728,7 @@ err_free_resource:
        pci_free_resource_list(&host->windows);
 err_remove_domain:
        irq_domain_remove(domain);
+       irq_domain_free_fwnode(fn);
        return err;
 }
 
@@ -735,8 +736,10 @@ static int bridge_remove(struct platform_device *pdev)
 {
        struct pci_bus *bus = platform_get_drvdata(pdev);
        struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       struct fwnode_handle *fn = bc->domain->fwnode;
 
        irq_domain_remove(bc->domain);
+       irq_domain_free_fwnode(fn);
        pci_lock_rescan_remove();
        pci_stop_root_bus(bus);
        pci_remove_root_bus(bus);
index 81ffcfbfaef2b2da2d7fd4175dad6fe88a534cd7..21325a4a78b92d6d03be3fc6e96a02ec91ad9b3a 100644 (file)
@@ -2335,8 +2335,13 @@ static int mp_irqdomain_create(int ioapic)
 
 static void ioapic_destroy_irqdomain(int idx)
 {
+       struct ioapic_domain_cfg *cfg = &ioapics[idx].irqdomain_cfg;
+       struct fwnode_handle *fn = ioapics[idx].irqdomain->fwnode;
+
        if (ioapics[idx].irqdomain) {
                irq_domain_remove(ioapics[idx].irqdomain);
+               if (!cfg->dev)
+                       irq_domain_free_fwnode(fn);
                ioapics[idx].irqdomain = NULL;
        }
 }
index 9564d23d094f05d36ee349bff704b31cce5af3e4..aa096b333a9914300eb3c6fe04c38f1bd6b41261 100644 (file)
@@ -628,13 +628,21 @@ out_free_table:
 
 static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
 {
+       struct fwnode_handle *fn;
+
        if (iommu && iommu->ir_table) {
                if (iommu->ir_msi_domain) {
+                       fn = iommu->ir_msi_domain->fwnode;
+
                        irq_domain_remove(iommu->ir_msi_domain);
+                       irq_domain_free_fwnode(fn);
                        iommu->ir_msi_domain = NULL;
                }
                if (iommu->ir_domain) {
+                       fn = iommu->ir_domain->fwnode;
+
                        irq_domain_remove(iommu->ir_domain);
+                       irq_domain_free_fwnode(fn);
                        iommu->ir_domain = NULL;
                }
                free_pages((unsigned long)iommu->ir_table->base,
index 74cee7cb0afc994306cf4462d7ed289121b80c1e..d939ccc4650994a7f7bca8eab74ab5d20075ede7 100644 (file)
@@ -616,7 +616,10 @@ static int ioc3_mfd_probe(struct pci_dev *pdev,
                /* Remove all already added MFD devices */
                mfd_remove_devices(&ipd->pdev->dev);
                if (ipd->domain) {
+                       struct fwnode_handle *fn = ipd->domain->fwnode;
+
                        irq_domain_remove(ipd->domain);
+                       irq_domain_free_fwnode(fn);
                        free_irq(ipd->domain_irq, (void *)ipd);
                }
                pci_iounmap(pdev, regs);
@@ -643,7 +646,10 @@ static void ioc3_mfd_remove(struct pci_dev *pdev)
        /* Release resources */
        mfd_remove_devices(&ipd->pdev->dev);
        if (ipd->domain) {
+               struct fwnode_handle *fn = ipd->domain->fwnode;
+
                irq_domain_remove(ipd->domain);
+               irq_domain_free_fwnode(fn);
                free_irq(ipd->domain_irq, (void *)ipd);
        }
        pci_iounmap(pdev, ipd->regs);
index 9a64cf90c291b13d1d9cc4c548c131a11885df52..ebec0a6e77ed041f546981d4bfcdd7cb0bf48142 100644 (file)
@@ -560,6 +560,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
        if (!vmd->bus) {
                pci_free_resource_list(&resources);
                irq_domain_remove(vmd->irq_domain);
+               irq_domain_free_fwnode(fn);
                return -ENODEV;
        }
 
@@ -673,6 +674,7 @@ static void vmd_cleanup_srcu(struct vmd_dev *vmd)
 static void vmd_remove(struct pci_dev *dev)
 {
        struct vmd_dev *vmd = pci_get_drvdata(dev);
+       struct fwnode_handle *fn = vmd->irq_domain->fwnode;
 
        sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
        pci_stop_root_bus(vmd->bus);
@@ -680,6 +682,7 @@ static void vmd_remove(struct pci_dev *dev)
        vmd_cleanup_srcu(vmd);
        vmd_detach_resources(vmd);
        irq_domain_remove(vmd->irq_domain);
+       irq_domain_free_fwnode(fn);
 }
 
 #ifdef CONFIG_PM_SLEEP