| From 85f83e48729185fd48f495969557349a8151fba1 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 21 Aug 2019 16:26:53 +1000 |
| Subject: powerpc/sriov: Remove VF eeh_dev state when disabling SR-IOV |
| |
| From: Oliver O'Halloran <oohall@gmail.com> |
| |
| [ Upstream commit 1fb4124ca9d456656a324f1ee29b7bf942f59ac8 ] |
| |
| When disabling virtual functions on an SR-IOV adapter we currently do not |
| correctly remove the EEH state for the now-dead virtual functions. When |
| removing the pci_dn that was created for the VF when SR-IOV was enabled |
| we free the corresponding eeh_dev without removing it from the child device |
| list of the eeh_pe that contained it. This can result in crashes due to the |
| use-after-free. |
| |
| Signed-off-by: Oliver O'Halloran <oohall@gmail.com> |
| Reviewed-by: Sam Bobroff <sbobroff@linux.ibm.com> |
| Tested-by: Sam Bobroff <sbobroff@linux.ibm.com> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Link: https://lore.kernel.org/r/20190821062655.19735-1-oohall@gmail.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/powerpc/kernel/pci_dn.c | 15 ++++++++++++++- |
| 1 file changed, 14 insertions(+), 1 deletion(-) |
| |
| diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c |
| index 9524009ca1ae4..d876eda926094 100644 |
| --- a/arch/powerpc/kernel/pci_dn.c |
| +++ b/arch/powerpc/kernel/pci_dn.c |
| @@ -244,9 +244,22 @@ void remove_dev_pci_data(struct pci_dev *pdev) |
| continue; |
| |
| #ifdef CONFIG_EEH |
| - /* Release EEH device for the VF */ |
| + /* |
| + * Release EEH state for this VF. The PCI core |
| + * has already torn down the pci_dev for this VF, but |
| + * we're responsible to removing the eeh_dev since it |
| + * has the same lifetime as the pci_dn that spawned it. |
| + */ |
| edev = pdn_to_eeh_dev(pdn); |
| if (edev) { |
| + /* |
| + * We allocate pci_dn's for the totalvfs count, |
| + * but only only the vfs that were activated |
| + * have a configured PE. |
| + */ |
| + if (edev->pe) |
| + eeh_rmv_from_parent_pe(edev); |
| + |
| pdn->edev = NULL; |
| kfree(edev); |
| } |
| -- |
| 2.20.1 |
| |