| From c9b12b59e2ea4c3c7cedec7efb071b649652f3a9 Mon Sep 17 00:00:00 2001 |
| From: Sven Schnelle <svens@linux.ibm.com> |
| Date: Mon, 6 Dec 2021 11:50:16 +0100 |
| Subject: s390/entry: fix duplicate tracking of irq nesting level |
| |
| From: Sven Schnelle <svens@linux.ibm.com> |
| |
| commit c9b12b59e2ea4c3c7cedec7efb071b649652f3a9 upstream. |
| |
| In the current code, when exiting from idle, rcu_irq_enter() is |
| called twice during irq entry: |
| |
| irq_entry_enter()-> rcu_irq_enter() |
| irq_enter() -> rcu_irq_enter() |
| |
| This may lead to wrong results from rcu_is_cpu_rrupt_from_idle() |
| because of a wrong dynticks nmi nesting count. Fix this by only |
| calling irq_enter_rcu(). |
| |
| Cc: <stable@vger.kernel.org> # 5.12+ |
| Reported-by: Mark Rutland <mark.rutland@arm.com> |
| Fixes: 56e62a737028 ("s390: convert to generic entry") |
| Signed-off-by: Sven Schnelle <svens@linux.ibm.com> |
| Signed-off-by: Heiko Carstens <hca@linux.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/s390/kernel/irq.c | 9 +++++---- |
| 1 file changed, 5 insertions(+), 4 deletions(-) |
| |
| --- a/arch/s390/kernel/irq.c |
| +++ b/arch/s390/kernel/irq.c |
| @@ -138,7 +138,7 @@ void noinstr do_io_irq(struct pt_regs *r |
| struct pt_regs *old_regs = set_irq_regs(regs); |
| int from_idle; |
| |
| - irq_enter(); |
| + irq_enter_rcu(); |
| |
| if (user_mode(regs)) |
| update_timer_sys(); |
| @@ -155,7 +155,8 @@ void noinstr do_io_irq(struct pt_regs *r |
| do_irq_async(regs, IO_INTERRUPT); |
| } while (MACHINE_IS_LPAR && irq_pending(regs)); |
| |
| - irq_exit(); |
| + irq_exit_rcu(); |
| + |
| set_irq_regs(old_regs); |
| irqentry_exit(regs, state); |
| |
| @@ -169,7 +170,7 @@ void noinstr do_ext_irq(struct pt_regs * |
| struct pt_regs *old_regs = set_irq_regs(regs); |
| int from_idle; |
| |
| - irq_enter(); |
| + irq_enter_rcu(); |
| |
| if (user_mode(regs)) |
| update_timer_sys(); |
| @@ -184,7 +185,7 @@ void noinstr do_ext_irq(struct pt_regs * |
| |
| do_irq_async(regs, EXT_INTERRUPT); |
| |
| - irq_exit(); |
| + irq_exit_rcu(); |
| set_irq_regs(old_regs); |
| irqentry_exit(regs, state); |
| |