stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Oliver O'Halloran <oohall@gmail.com>,
	Michael Ellerman <mpe@ellerman.id.au>,
	Sasha Levin <sashal@kernel.org>,
	linuxppc-dev@lists.ozlabs.org
Subject: [PATCH AUTOSEL 5.2 52/70] powerpc/eeh: Clean up EEH PEs after recovery finishes
Date: Tue, 24 Sep 2019 12:45:31 -0400	[thread overview]
Message-ID: <20190924164549.27058-52-sashal@kernel.org> (raw)
In-Reply-To: <20190924164549.27058-1-sashal@kernel.org>

From: Oliver O'Halloran <oohall@gmail.com>

[ Upstream commit 799abe283e5103d48e079149579b4f167c95ea0e ]

When the last device in an eeh_pe is removed the eeh_pe structure itself
(and any empty parents) are freed since they are no longer needed. This
results in a crash when a hotplug driver is involved since the following
may occur:

1. Device is suprise removed.
2. Driver performs an MMIO, which fails and queues and eeh_event.
3. Hotplug driver receives a hotplug interrupt and removes any
   pci_devs that were under the slot.
4. pci_dev is torn down and the eeh_pe is freed.
5. The EEH event handler thread processes the eeh_event and crashes
   since the eeh_pe pointer in the eeh_event structure is no
   longer valid.

Crashing is generally considered poor form. Instead of doing that use
the fact PEs are marked as EEH_PE_INVALID to keep them around until the
end of the recovery cycle, at which point we can safely prune any empty
PEs.

Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20190903101605.2890-2-oohall@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 arch/powerpc/kernel/eeh_driver.c | 36 ++++++++++++++++++++++++++++++--
 arch/powerpc/kernel/eeh_event.c  |  8 +++++++
 arch/powerpc/kernel/eeh_pe.c     | 23 +++++++++++++++++++-
 3 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 1fbe541856f5e..fe0c32fb9f96f 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -744,6 +744,33 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
  */
 #define MAX_WAIT_FOR_RECOVERY 300
 
+
+/* Walks the PE tree after processing an event to remove any stale PEs.
+ *
+ * NB: This needs to be recursive to ensure the leaf PEs get removed
+ * before their parents do. Although this is possible to do recursively
+ * we don't since this is easier to read and we need to garantee
+ * the leaf nodes will be handled first.
+ */
+static void eeh_pe_cleanup(struct eeh_pe *pe)
+{
+	struct eeh_pe *child_pe, *tmp;
+
+	list_for_each_entry_safe(child_pe, tmp, &pe->child_list, child)
+		eeh_pe_cleanup(child_pe);
+
+	if (pe->state & EEH_PE_KEEP)
+		return;
+
+	if (!(pe->state & EEH_PE_INVALID))
+		return;
+
+	if (list_empty(&pe->edevs) && list_empty(&pe->child_list)) {
+		list_del(&pe->child);
+		kfree(pe);
+	}
+}
+
 /**
  * eeh_handle_normal_event - Handle EEH events on a specific PE
  * @pe: EEH PE - which should not be used after we return, as it may
@@ -782,8 +809,6 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
 		return;
 	}
 
-	eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
-
 	eeh_pe_update_time_stamp(pe);
 	pe->freeze_count++;
 	if (pe->freeze_count > eeh_max_freezes) {
@@ -973,6 +998,12 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
 			return;
 		}
 	}
+
+	/*
+	 * Clean up any PEs without devices. While marked as EEH_PE_RECOVERYING
+	 * we don't want to modify the PE tree structure so we do it here.
+	 */
+	eeh_pe_cleanup(pe);
 	eeh_pe_state_clear(pe, EEH_PE_RECOVERING, true);
 }
 
@@ -1045,6 +1076,7 @@ void eeh_handle_special_event(void)
 		 */
 		if (rc == EEH_NEXT_ERR_FROZEN_PE ||
 		    rc == EEH_NEXT_ERR_FENCED_PHB) {
+			eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
 			eeh_handle_normal_event(pe);
 		} else {
 			pci_lock_rescan_remove();
diff --git a/arch/powerpc/kernel/eeh_event.c b/arch/powerpc/kernel/eeh_event.c
index 64cfbe41174b2..e36653e5f76b3 100644
--- a/arch/powerpc/kernel/eeh_event.c
+++ b/arch/powerpc/kernel/eeh_event.c
@@ -121,6 +121,14 @@ int __eeh_send_failure_event(struct eeh_pe *pe)
 	}
 	event->pe = pe;
 
+	/*
+	 * Mark the PE as recovering before inserting it in the queue.
+	 * This prevents the PE from being free()ed by a hotplug driver
+	 * while the PE is sitting in the event queue.
+	 */
+	if (pe)
+		eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
+
 	/* We may or may not be called in an interrupt context */
 	spin_lock_irqsave(&eeh_eventlist_lock, flags);
 	list_add(&event->list, &eeh_eventlist);
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 854cef7b18f4d..f0813d50e0b1c 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -491,6 +491,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
 int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
 {
 	struct eeh_pe *pe, *parent, *child;
+	bool keep, recover;
 	int cnt;
 	struct pci_dn *pdn = eeh_dev_to_pdn(edev);
 
@@ -516,10 +517,21 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
 	 */
 	while (1) {
 		parent = pe->parent;
+
+		/* PHB PEs should never be removed */
 		if (pe->type & EEH_PE_PHB)
 			break;
 
-		if (!(pe->state & EEH_PE_KEEP)) {
+		/*
+		 * XXX: KEEP is set while resetting a PE. I don't think it's
+		 * ever set without RECOVERING also being set. I could
+		 * be wrong though so catch that with a WARN.
+		 */
+		keep = !!(pe->state & EEH_PE_KEEP);
+		recover = !!(pe->state & EEH_PE_RECOVERING);
+		WARN_ON(keep && !recover);
+
+		if (!keep && !recover) {
 			if (list_empty(&pe->edevs) &&
 			    list_empty(&pe->child_list)) {
 				list_del(&pe->child);
@@ -528,6 +540,15 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
 				break;
 			}
 		} else {
+			/*
+			 * Mark the PE as invalid. At the end of the recovery
+			 * process any invalid PEs will be garbage collected.
+			 *
+			 * We need to delay the free()ing of them since we can
+			 * remove edev's while traversing the PE tree which
+			 * might trigger the removal of a PE and we can't
+			 * deal with that (yet).
+			 */
 			if (list_empty(&pe->edevs)) {
 				cnt = 0;
 				list_for_each_entry(child, &pe->child_list, child) {
-- 
2.20.1


  parent reply	other threads:[~2019-09-24 16:48 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-24 16:44 [PATCH AUTOSEL 5.2 01/70] drm/vkms: Fix crc worker races Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 02/70] drm/bridge: tc358767: Increase AUX transfer length limit Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 03/70] drm/bridge: adv7511: Attach to DSI host at probe time Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 04/70] drm/kms: Catch mode_object lifetime errors Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 05/70] drm/vkms: Avoid assigning 0 for possible_crtc Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 06/70] drm/panel: simple: fix AUO g185han01 horizontal blanking Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 07/70] drm/amd/display: add monitor patch to add T7 delay Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 08/70] video: ssd1307fb: Start page range at page_offset Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 09/70] drm/tinydrm/Kconfig: drivers: Select BACKLIGHT_CLASS_DEVICE Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 10/70] drm/stm: attach gem fence to atomic state Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 11/70] drm/panel: check failure cases in the probe func Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 12/70] drm/rockchip: Check for fast link training before enabling psr Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 13/70] drm/amdgpu: Fix hard hang for S/G display BOs Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 14/70] drm/radeon: Fix EEH during kexec Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 15/70] gpu: drm: radeon: Fix a possible null-pointer dereference in radeon_connector_set_property() Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 16/70] clk: imx8mq: Mark AHB clock as critical Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 17/70] PCI: rpaphp: Avoid a sometimes-uninitialized warning Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 18/70] pinctrl: stmfx: update pinconf settings Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 19/70] ipmi_si: Only schedule continuously in the thread in maintenance mode Sasha Levin
2019-09-24 16:44 ` [PATCH AUTOSEL 5.2 20/70] clk: qoriq: Fix -Wunused-const-variable Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 21/70] clk: sunxi-ng: v3s: add missing clock slices for MMC2 module clocks Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 22/70] drm/amd/display: fix issue where 252-255 values are clipped Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 23/70] drm/amd/display: Fix frames_to_insert math Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 24/70] drm/amd/display: reprogram VM config when system resume Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 25/70] powerpc/powernv/ioda2: Allocate TCE table levels on demand for default DMA window Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 26/70] drm/amd/powerplay/smu7: enforce minimal VBITimeout (v2) Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 27/70] clk: actions: Don't reference clk_init_data after registration Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 28/70] clk: sirf: " Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 29/70] clk: meson: axg-audio: " Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 30/70] clk: sprd: " Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 31/70] clk: zx296718: " Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 32/70] powerpc/xmon: Check for HV mode when dumping XIVE info from OPAL Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 33/70] powerpc/rtas: use device model APIs and serialization during LPM Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 34/70] powerpc/futex: Fix warning: 'oldval' may be used uninitialized in this function Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 35/70] powerpc/64s/radix: Remove redundant pfn_pte bitop, add VM_BUG_ON Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 36/70] powerpc/64s/radix: Fix memory hotplug section page table creation Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 37/70] powerpc/pseries/mobility: use cond_resched when updating device tree Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 38/70] powerpc/perf: fix imc allocation failure handling Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 39/70] pinctrl: tegra: Fix write barrier placement in pmx_writel Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 40/70] powerpc/eeh: Clear stale EEH_DEV_NO_HANDLER flag Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 41/70] vfio_pci: Restore original state on release Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 42/70] drm/nouveau/kms/tu102-: disable input lut when input is already FP16 Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 43/70] drm/nouveau/volt: Fix for some cards having 0 maximum voltage Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 44/70] pinctrl: amd: disable spurious-firing GPIO IRQs Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 45/70] clk: renesas: mstp: Set GENPD_FLAG_ALWAYS_ON for clock domain Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 46/70] clk: renesas: cpg-mssr: " Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 47/70] drm/amd/display: support spdif Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 48/70] selftests/powerpc: Retry on host facility unavailable Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 49/70] drm/amdgpu/si: fix ASIC tests Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 50/70] powerpc/64s/exception: machine check use correct cfar for late handler Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 51/70] pstore: fs superblock limits Sasha Levin
2019-09-24 16:45 ` Sasha Levin [this message]
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 53/70] powerpc/imc: Dont create debugfs files for cpu-less nodes Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 54/70] clk: qcom: gcc-sdm845: Use floor ops for sdcc clks Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 55/70] powerpc/pseries: correctly track irq state in default idle Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 56/70] pinctrl: meson-gxbb: Fix wrong pinning definition for uart_c Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 57/70] mailbox: mediatek: cmdq: clear the event in cmdq initial flow Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 58/70] arm64: fix unreachable code issue with cmpxchg Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 59/70] clk: at91: select parent if main oscillator or bypass is enabled Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 60/70] clk: imx: pll14xx: avoid glitch when set rate Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 61/70] clk: imx: clk-pll14xx: unbypass PLL by default Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 62/70] clk: Make clk_bulk_get_all() return a valid "id" Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 63/70] powerpc: dump kernel log before carrying out fadump or kdump Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 64/70] mbox: qcom: add APCS child device for QCS404 Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 65/70] clk: sprd: add missing kfree Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 66/70] scsi: core: Reduce memory required for SCSI logging Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 67/70] dma-buf/sw_sync: Synchronize signal vs syncpt free Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 68/70] drm: fix module name in edid_firmware log message Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 69/70] f2fs: fix to drop meta/node pages during umount Sasha Levin
2019-09-24 16:45 ` [PATCH AUTOSEL 5.2 70/70] ext4: fix potential use after free after remounting with noblock_validity Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190924164549.27058-52-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mpe@ellerman.id.au \
    --cc=oohall@gmail.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).