Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp725167pxb; Tue, 2 Feb 2021 16:48:15 -0800 (PST) X-Google-Smtp-Source: ABdhPJwrquE5BZIZkbbubb6iC8thDCoi0/3ID6hT9YeriK5c2SZ9m9ZUgD8ogm1Al8iegzthDPYR X-Received: by 2002:aa7:c44f:: with SMTP id n15mr681122edr.150.1612313295148; Tue, 02 Feb 2021 16:48:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1612313295; cv=none; d=google.com; s=arc-20160816; b=fugXSund6VZIeu/YoDx3ki0wLfsBwkGDY77K8a+bDheKT7qXnYb7ZmzGYBtNRuig/j 7+zvuno7r5T8Imb+5ZedoZSqfvbzzQ8leE9nBcs5TLBpBzQeiRpbbQt4I5qC7MBZSlMV cOg1riwDDcJz/4E+ra8LitxDRvxihSLrEnoX0nI01FW/F/WXGcKGVsNiO/Per2exdHsp tNVU0/NzXlDKPgGN4BUVRcRaTjTPhN0Zvm6qd4x5SkuByxidGWaSwBXdbwLrkkbUiJ+H wlqgGvoPVupWGs+u6c4LVvr2Q/gA3L4jISKy9ygXqBOYA85bjHUON5rNIgenl4DO491z fidA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=AdAaiVGqPDEahfgjkEKW9I9njv3xhYuy5o0bqIJT+/E=; b=rMS6DU14QJkyMzCzmhT4GzkqUfcxjCSEvpQ2KWwkQ38u3ytu6SGYLr2+Y9J0rItr7D zRl7PfGcYi/5AIbDH6RmTdAe9szXlyrQie5Etvi+R5zvT6hKDGUw9NVzdwoprzCELbQu pPWUIAM03FbDg2kGNnu0wFa5gFOGKN1jeRBOH/hVbmGsS0aUUZNF0hV9I3biYjTVTFGv MecJxvmcfAdSHNzsrkb7egvVqs2rCpBPMcsjjk+gJZEzPUqoWWpvcpUDkzbPa8S66BdC HX4CQuNTyqGpCUxUAmdXQAPKg6gxpgqaLeHJrl4W+RrYfzUwq9HiHosuvxSlEP4723tg kmpA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=zzvZJKZq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id a66si247086edf.607.2021.02.02.16.47.51; Tue, 02 Feb 2021 16:48:15 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=zzvZJKZq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240151AbhBBTwH (ORCPT + 99 others); Tue, 2 Feb 2021 14:52:07 -0500 Received: from mail.kernel.org ([198.145.29.99]:40856 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233120AbhBBNvn (ORCPT ); Tue, 2 Feb 2021 08:51:43 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id B7DFC64FBA; Tue, 2 Feb 2021 13:43:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1612273408; bh=RwMlqxsNOf7MJEbJCm7Yga/VY3R+118Kq4RXQrM1y30=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=zzvZJKZqCn6eZJP8o7QNwpXyrvzWcAJzSGP67qxVv/e/ApQR5ZmznkZ5aiYFH8fuV 1trzE36Y69XqoSde/23zC/L9c3nRMGydYB6rgylragQgCFSPD7gIvCxXAkyGSbHwWd SsByQem5PWBg0wJVbK7lbd72jjW86SFZXX/2hYVE= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Nicholas Piggin , Michael Ellerman , Sasha Levin Subject: [PATCH 5.10 095/142] powerpc/64s: prevent recursive replay_soft_interrupts causing superfluous interrupt Date: Tue, 2 Feb 2021 14:37:38 +0100 Message-Id: <20210202133001.630900187@linuxfoundation.org> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210202132957.692094111@linuxfoundation.org> References: <20210202132957.692094111@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Nicholas Piggin [ Upstream commit 4025c784c573cab7e3f84746cc82b8033923ec62 ] When an asynchronous interrupt calls irq_exit, it checks for softirqs that may have been created, and runs them. Running softirqs enables local irqs, which can replay pending interrupts causing recursion in replay_soft_interrupts. This abridged trace shows how this can occur: ! NIP replay_soft_interrupts LR interrupt_exit_kernel_prepare Call Trace: interrupt_exit_kernel_prepare (unreliable) interrupt_return --- interrupt: ea0 at __rb_reserve_next NIP __rb_reserve_next LR __rb_reserve_next Call Trace: ring_buffer_lock_reserve trace_function function_trace_call ftrace_call __do_softirq irq_exit timer_interrupt ! replay_soft_interrupts interrupt_exit_kernel_prepare interrupt_return --- interrupt: ea0 at arch_local_irq_restore This can not be prevented easily, because softirqs must not block hard irqs, so it has to be dealt with. The recursion is bounded by design in the softirq code because softirq replay disables softirqs and loops around again to check for new softirqs created while it ran, so that's not a problem. However it does mess up interrupt replay state, causing superfluous interrupts when the second replay_soft_interrupts clears a pending interrupt, leaving it still set in the first call in the 'happened' local variable. Fix this by not caching a copy of irqs_happened across interrupt handler calls. Fixes: 3282a3da25bd ("powerpc/64: Implement soft interrupt replay in C") Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20210123061244.2076145-1-npiggin@gmail.com Signed-off-by: Sasha Levin --- arch/powerpc/kernel/irq.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 6b1eca53e36cc..cc7a6271b6b4e 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -180,13 +180,18 @@ void notrace restore_interrupts(void) void replay_soft_interrupts(void) { + struct pt_regs regs; + /* - * We use local_paca rather than get_paca() to avoid all - * the debug_smp_processor_id() business in this low level - * function + * Be careful here, calling these interrupt handlers can cause + * softirqs to be raised, which they may run when calling irq_exit, + * which will cause local_irq_enable() to be run, which can then + * recurse into this function. Don't keep any state across + * interrupt handler calls which may change underneath us. + * + * We use local_paca rather than get_paca() to avoid all the + * debug_smp_processor_id() business in this low level function. */ - unsigned char happened = local_paca->irq_happened; - struct pt_regs regs; ppc_save_regs(®s); regs.softe = IRQS_ENABLED; @@ -209,7 +214,7 @@ again: * This is a higher priority interrupt than the others, so * replay it first. */ - if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_HMI)) { + if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) { local_paca->irq_happened &= ~PACA_IRQ_HMI; regs.trap = 0xe60; handle_hmi_exception(®s); @@ -217,7 +222,7 @@ again: hard_irq_disable(); } - if (happened & PACA_IRQ_DEC) { + if (local_paca->irq_happened & PACA_IRQ_DEC) { local_paca->irq_happened &= ~PACA_IRQ_DEC; regs.trap = 0x900; timer_interrupt(®s); @@ -225,7 +230,7 @@ again: hard_irq_disable(); } - if (happened & PACA_IRQ_EE) { + if (local_paca->irq_happened & PACA_IRQ_EE) { local_paca->irq_happened &= ~PACA_IRQ_EE; regs.trap = 0x500; do_IRQ(®s); @@ -233,7 +238,7 @@ again: hard_irq_disable(); } - if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) { + if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) { local_paca->irq_happened &= ~PACA_IRQ_DBELL; if (IS_ENABLED(CONFIG_PPC_BOOK3E)) regs.trap = 0x280; @@ -245,7 +250,7 @@ again: } /* Book3E does not support soft-masking PMI interrupts */ - if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_PMI)) { + if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) { local_paca->irq_happened &= ~PACA_IRQ_PMI; regs.trap = 0xf00; performance_monitor_exception(®s); @@ -253,8 +258,7 @@ again: hard_irq_disable(); } - happened = local_paca->irq_happened; - if (happened & ~PACA_IRQ_HARD_DIS) { + if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) { /* * We are responding to the next interrupt, so interrupt-off * latencies should be reset here. -- 2.27.0