As we may switch the Linux context as a result of calling __ipipe_dispatch_event and, thus, may leave it with a different root domain state independent of the return code, we have to call __fixup_if unconditionally. Moreover, we should also always check for pending VIRQs on return.
Signed-off-by: Jan Kiszka <[email protected]> --- arch/x86/kernel/ipipe.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) Index: b/arch/x86/kernel/ipipe.c =================================================================== --- a/arch/x86/kernel/ipipe.c +++ b/arch/x86/kernel/ipipe.c @@ -540,6 +540,7 @@ asmlinkage void __ipipe_unstall_iret_roo asmlinkage int __ipipe_syscall_root(struct pt_regs regs) { unsigned long flags; + int dont_pass; __fixup_if(®s); @@ -551,8 +552,9 @@ asmlinkage int __ipipe_syscall_root(stru tail work has to be performed (for handling signals etc). */ if (__ipipe_syscall_watched_p(current, regs.orig_ax) && - __ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) && - __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,®s) > 0) { + __ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL)) { + dont_pass = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,®s); + /* We might enter here over a non-root domain and exit * over the root one as a result of the syscall * (i.e. by recycling the register set of the current @@ -568,9 +570,10 @@ asmlinkage int __ipipe_syscall_root(stru if ((ipipe_root_cpudom_var(irqpend_himask) & IPIPE_IRQMASK_VIRT) != 0) __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT); local_irq_restore_hw(flags); - return -1; - } - return 1; + if (dont_pass) + return -1; + } else if (dont_pass) + return 1; } return 0; @@ -610,6 +613,7 @@ asmlinkage int __ipipe_preempt_schedule_ asmlinkage int __ipipe_syscall_root(struct pt_regs *regs) { unsigned long flags; + int pass; __fixup_if(regs); @@ -621,8 +625,9 @@ asmlinkage int __ipipe_syscall_root(stru tail work has to be performed (for handling signals etc). */ if (__ipipe_syscall_watched_p(current, regs->orig_ax) && - __ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) && - __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs) > 0) { + __ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL)) { + pass = !__ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs); + /* We might enter here over a non-root domain and exit * over the root one as a result of the syscall * (i.e. by recycling the register set of the current @@ -632,6 +637,9 @@ asmlinkage int __ipipe_syscall_root(stru * stall bit on exit. */ __fixup_if(regs); + if (pass) + return 0; + if (ipipe_root_domain_p && !in_atomic()) { /* Sync pending VIRQs before _TIF_NEED_RESCHED is tested. */ local_irq_save_hw(flags); @@ -648,7 +656,7 @@ asmlinkage int __ipipe_syscall_root(stru return 1; } - return 0; + return 0; } #endif /* !CONFIG_X86_32 */ _______________________________________________ Adeos-main mailing list [email protected] https://mail.gna.org/listinfo/adeos-main
