Skip to content

Commit ec01608

Browse files
Jon DerrickKAGA-KOKO
authored andcommitted
irqdomain/treewide: Free firmware node after domain removal
Commit 711419e ("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 e3beca4 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: e3beca4 ("irqdomain/treewide: Keep firmware node unconditionally allocated") Signed-off-by: Jon Derrick <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Acked-by: Bjorn Helgaas <[email protected]> # drivers/pci Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent ba47d84 commit ec01608

File tree

5 files changed

+25
-0
lines changed

5 files changed

+25
-0
lines changed

arch/mips/pci/pci-xtalk-bridge.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,15 +728,18 @@ static int bridge_probe(struct platform_device *pdev)
728728
pci_free_resource_list(&host->windows);
729729
err_remove_domain:
730730
irq_domain_remove(domain);
731+
irq_domain_free_fwnode(fn);
731732
return err;
732733
}
733734

734735
static int bridge_remove(struct platform_device *pdev)
735736
{
736737
struct pci_bus *bus = platform_get_drvdata(pdev);
737738
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
739+
struct fwnode_handle *fn = bc->domain->fwnode;
738740

739741
irq_domain_remove(bc->domain);
742+
irq_domain_free_fwnode(fn);
740743
pci_lock_rescan_remove();
741744
pci_stop_root_bus(bus);
742745
pci_remove_root_bus(bus);

arch/x86/kernel/apic/io_apic.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,8 +2335,13 @@ static int mp_irqdomain_create(int ioapic)
23352335

23362336
static void ioapic_destroy_irqdomain(int idx)
23372337
{
2338+
struct ioapic_domain_cfg *cfg = &ioapics[idx].irqdomain_cfg;
2339+
struct fwnode_handle *fn = ioapics[idx].irqdomain->fwnode;
2340+
23382341
if (ioapics[idx].irqdomain) {
23392342
irq_domain_remove(ioapics[idx].irqdomain);
2343+
if (!cfg->dev)
2344+
irq_domain_free_fwnode(fn);
23402345
ioapics[idx].irqdomain = NULL;
23412346
}
23422347
}

drivers/iommu/intel/irq_remapping.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,13 +628,21 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
628628

629629
static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
630630
{
631+
struct fwnode_handle *fn;
632+
631633
if (iommu && iommu->ir_table) {
632634
if (iommu->ir_msi_domain) {
635+
fn = iommu->ir_msi_domain->fwnode;
636+
633637
irq_domain_remove(iommu->ir_msi_domain);
638+
irq_domain_free_fwnode(fn);
634639
iommu->ir_msi_domain = NULL;
635640
}
636641
if (iommu->ir_domain) {
642+
fn = iommu->ir_domain->fwnode;
643+
637644
irq_domain_remove(iommu->ir_domain);
645+
irq_domain_free_fwnode(fn);
638646
iommu->ir_domain = NULL;
639647
}
640648
free_pages((unsigned long)iommu->ir_table->base,

drivers/mfd/ioc3.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,10 @@ static int ioc3_mfd_probe(struct pci_dev *pdev,
616616
/* Remove all already added MFD devices */
617617
mfd_remove_devices(&ipd->pdev->dev);
618618
if (ipd->domain) {
619+
struct fwnode_handle *fn = ipd->domain->fwnode;
620+
619621
irq_domain_remove(ipd->domain);
622+
irq_domain_free_fwnode(fn);
620623
free_irq(ipd->domain_irq, (void *)ipd);
621624
}
622625
pci_iounmap(pdev, regs);
@@ -643,7 +646,10 @@ static void ioc3_mfd_remove(struct pci_dev *pdev)
643646
/* Release resources */
644647
mfd_remove_devices(&ipd->pdev->dev);
645648
if (ipd->domain) {
649+
struct fwnode_handle *fn = ipd->domain->fwnode;
650+
646651
irq_domain_remove(ipd->domain);
652+
irq_domain_free_fwnode(fn);
647653
free_irq(ipd->domain_irq, (void *)ipd);
648654
}
649655
pci_iounmap(pdev, ipd->regs);

drivers/pci/controller/vmd.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
560560
if (!vmd->bus) {
561561
pci_free_resource_list(&resources);
562562
irq_domain_remove(vmd->irq_domain);
563+
irq_domain_free_fwnode(fn);
563564
return -ENODEV;
564565
}
565566

@@ -673,13 +674,15 @@ static void vmd_cleanup_srcu(struct vmd_dev *vmd)
673674
static void vmd_remove(struct pci_dev *dev)
674675
{
675676
struct vmd_dev *vmd = pci_get_drvdata(dev);
677+
struct fwnode_handle *fn = vmd->irq_domain->fwnode;
676678

677679
sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
678680
pci_stop_root_bus(vmd->bus);
679681
pci_remove_root_bus(vmd->bus);
680682
vmd_cleanup_srcu(vmd);
681683
vmd_detach_resources(vmd);
682684
irq_domain_remove(vmd->irq_domain);
685+
irq_domain_free_fwnode(fn);
683686
}
684687

685688
#ifdef CONFIG_PM_SLEEP

0 commit comments

Comments
 (0)