When ACPI APEI/GHES processes PCIe AER error records, it allocates memory
for aer_capability_regs (entry.regs) from ghes_estatus_pool and queues
the entry into aer_recover_ring.

In aer_recover_work_func(), items are popped from aer_recover_ring via
kfifo_get(). If pci_get_domain_bus_and_slot() fails to find a matching
pci_dev, the code previously executed 'continue', bypassing the call to
ghes_estatus_pool_region_free(). As a result, the memory allocated for
entry.regs from ghes_estatus_pool was leaked.

Refactor aer_recover_work_func() to ensure ghes_estatus_pool_region_free()
is called unconditionally for every dequeued entry, releasing the pool
memory even when pci_dev is missing.

Signed-off-by: Priyank Rathod <[email protected]>
---
 drivers/pci/pcie/aer.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 967cde9dd519..9683cdef649b 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1223,14 +1223,13 @@ static void aer_recover_work_func(struct work_struct 
*work)
        while (kfifo_get(&aer_recover_ring, &entry)) {
                pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
                                                   entry.devfn);
-               if (!pdev) {
+               if (!pdev)
                        pr_err_ratelimited("%04x:%02x:%02x.%x: no pci_dev 
found\n",
                                           entry.domain, entry.bus,
                                           PCI_SLOT(entry.devfn),
                                           PCI_FUNC(entry.devfn));
-                       continue;
-               }
-               pci_print_aer(pdev, entry.severity, entry.regs);
+               else
+                       pci_print_aer(pdev, entry.severity, entry.regs);
 
                /*
                 * Memory for aer_capability_regs(entry.regs) is being
@@ -1242,13 +1241,15 @@ static void aer_recover_work_func(struct work_struct 
*work)
                ghes_estatus_pool_region_free((unsigned long)entry.regs,
                                            sizeof(struct aer_capability_regs));
 
-               if (entry.severity == AER_NONFATAL)
-                       pcie_do_recovery(pdev, pci_channel_io_normal,
-                                        aer_root_reset);
-               else if (entry.severity == AER_FATAL)
-                       pcie_do_recovery(pdev, pci_channel_io_frozen,
-                                        aer_root_reset);
-               pci_dev_put(pdev);
+               if (pdev) {
+                       if (entry.severity == AER_NONFATAL)
+                               pcie_do_recovery(pdev, pci_channel_io_normal,
+                                                aer_root_reset);
+                       else if (entry.severity == AER_FATAL)
+                               pcie_do_recovery(pdev, pci_channel_io_frozen,
+                                                aer_root_reset);
+                       pci_dev_put(pdev);
+               }
        }
 }
 

-- 
2.55.0.571.g244d577d93-goog


Reply via email to