s390/entry: fix duplicate tracking of irq nesting level
commitc9b12b59e2
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:56e62a7370
("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>
This commit is contained in:
Родитель
b08b3bfcc7
Коммит
2eeff00926
|
@ -138,7 +138,7 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||||
int from_idle;
|
int from_idle;
|
||||||
|
|
||||||
irq_enter();
|
irq_enter_rcu();
|
||||||
|
|
||||||
if (user_mode(regs))
|
if (user_mode(regs))
|
||||||
update_timer_sys();
|
update_timer_sys();
|
||||||
|
@ -155,7 +155,8 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
||||||
do_irq_async(regs, IO_INTERRUPT);
|
do_irq_async(regs, IO_INTERRUPT);
|
||||||
} while (MACHINE_IS_LPAR && irq_pending(regs));
|
} while (MACHINE_IS_LPAR && irq_pending(regs));
|
||||||
|
|
||||||
irq_exit();
|
irq_exit_rcu();
|
||||||
|
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
irqentry_exit(regs, state);
|
irqentry_exit(regs, state);
|
||||||
|
|
||||||
|
@ -169,7 +170,7 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||||
int from_idle;
|
int from_idle;
|
||||||
|
|
||||||
irq_enter();
|
irq_enter_rcu();
|
||||||
|
|
||||||
if (user_mode(regs))
|
if (user_mode(regs))
|
||||||
update_timer_sys();
|
update_timer_sys();
|
||||||
|
@ -184,7 +185,7 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
||||||
|
|
||||||
do_irq_async(regs, EXT_INTERRUPT);
|
do_irq_async(regs, EXT_INTERRUPT);
|
||||||
|
|
||||||
irq_exit();
|
irq_exit_rcu();
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
irqentry_exit(regs, state);
|
irqentry_exit(regs, state);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче