From 898e34b34c5c2a3f944073b36861e2247c7fed58 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 7 Nov 2011 16:26:48 -0800 Subject: [PATCH] kernel - Fix itimer hard critical section panic * ksignal() needs per-lwp tokens as well as the process token, the existing itimer code only gets the process token. * Flag the itimer signal and issue the ksignal() in the trap's AST code instead of trying to issue it from the hardclock. Reported-by: swildner --- sys/kern/kern_clock.c | 19 ++++++++++++++----- sys/kern/kern_time.c | 8 ++++++++ sys/platform/pc32/i386/trap.c | 16 +++++++++++++--- sys/platform/pc64/x86_64/trap.c | 16 +++++++++++++--- sys/platform/vkernel/i386/trap.c | 19 +++++++++++++++---- sys/platform/vkernel64/x86_64/trap.c | 19 +++++++++++++++---- sys/sys/proc.h | 4 ++-- 7 files changed, 80 insertions(+), 21 deletions(-) diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 697b327ea9..63e995128a 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -554,17 +554,26 @@ hardclock(systimer_t info, int in_ipi __unused, struct intrframe *frame) * ITimer handling is per-tick, per-cpu. * * We must acquire the per-process token in order for ksignal() - * to be non-blocking. + * to be non-blocking. For the moment this requires an AST fault, + * the ksignal() cannot be safely issued from this hard interrupt. + * + * XXX Even the trytoken here isn't right, and itimer operation in + * a multi threaded environment is going to be weird at the + * very least. */ if ((p = curproc) != NULL && lwkt_trytoken(&p->p_token)) { crit_enter_hard(); if (frame && CLKF_USERMODE(frame) && timevalisset(&p->p_timer[ITIMER_VIRTUAL].it_value) && - itimerdecr(&p->p_timer[ITIMER_VIRTUAL], ustick) == 0) - ksignal(p, SIGVTALRM); + itimerdecr(&p->p_timer[ITIMER_VIRTUAL], ustick) == 0) { + p->p_flag |= P_SIGVTALRM; + need_user_resched(); + } if (timevalisset(&p->p_timer[ITIMER_PROF].it_value) && - itimerdecr(&p->p_timer[ITIMER_PROF], ustick) == 0) - ksignal(p, SIGPROF); + itimerdecr(&p->p_timer[ITIMER_PROF], ustick) == 0) { + p->p_flag |= P_SIGPROF; + need_user_resched(); + } crit_exit_hard(); lwkt_reltoken(&p->p_token); } diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index f454febc85..d77f93d98d 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -753,6 +753,14 @@ sys_setitimer(struct setitimer_args *uap) p->p_realtimer = aitv; } else { p->p_timer[uap->which] = aitv; + switch(uap->which) { + case ITIMER_VIRTUAL: + p->p_flag &= ~P_SIGVTALRM; + break; + case ITIMER_PROF: + p->p_flag &= ~P_SIGPROF; + break; + } } lwkt_reltoken(&p->p_token); return (0); diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index 2b4b900fe5..4676fbdf7c 100644 --- a/sys/platform/pc32/i386/trap.c +++ b/sys/platform/pc32/i386/trap.c @@ -273,10 +273,20 @@ recheck: * Post any pending upcalls. If running a virtual kernel be sure * to restore the virtual kernel's vmspace before posting the upcall. */ - if (p->p_flag & P_UPCALLPEND) { + if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) { lwkt_gettoken(&p->p_token); - p->p_flag &= ~P_UPCALLPEND; - postupcall(lp); + if (p->p_flag & P_SIGVTALRM) { + p->p_flag &= ~P_SIGVTALRM; + ksignal(p, SIGVTALRM); + } + if (p->p_flag & P_SIGPROF) { + p->p_flag &= ~P_SIGPROF; + ksignal(p, SIGPROF); + } + if (p->p_flag & P_UPCALLPEND) { + p->p_flag &= ~P_UPCALLPEND; + postupcall(lp); + } lwkt_reltoken(&p->p_token); goto recheck; } diff --git a/sys/platform/pc64/x86_64/trap.c b/sys/platform/pc64/x86_64/trap.c index 795fbfcfb9..cdde57dcb8 100644 --- a/sys/platform/pc64/x86_64/trap.c +++ b/sys/platform/pc64/x86_64/trap.c @@ -250,10 +250,20 @@ recheck: * Post any pending upcalls. If running a virtual kernel be sure * to restore the virtual kernel's vmspace before posting the upcall. */ - if (p->p_flag & P_UPCALLPEND) { + if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) { lwkt_gettoken(&p->p_token); - p->p_flag &= ~P_UPCALLPEND; - postupcall(lp); + if (p->p_flag & P_SIGVTALRM) { + p->p_flag &= ~P_SIGVTALRM; + ksignal(p, SIGVTALRM); + } + if (p->p_flag & P_SIGPROF) { + p->p_flag &= ~P_SIGPROF; + ksignal(p, SIGPROF); + } + if (p->p_flag & P_UPCALLPEND) { + p->p_flag &= ~P_UPCALLPEND; + postupcall(lp); + } lwkt_reltoken(&p->p_token); goto recheck; } diff --git a/sys/platform/vkernel/i386/trap.c b/sys/platform/vkernel/i386/trap.c index 3d36f4e442..9af511073f 100644 --- a/sys/platform/vkernel/i386/trap.c +++ b/sys/platform/vkernel/i386/trap.c @@ -244,12 +244,23 @@ recheck: } /* - * Post any pending upcalls + * Post any pending upcalls. If running a virtual kernel be sure + * to restore the virtual kernel's vmspace before posting the upcall. */ - if (p->p_flag & P_UPCALLPEND) { + if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) { lwkt_gettoken(&p->p_token); - p->p_flag &= ~P_UPCALLPEND; - postupcall(lp); + if (p->p_flag & P_SIGVTALRM) { + p->p_flag &= ~P_SIGVTALRM; + ksignal(p, SIGVTALRM); + } + if (p->p_flag & P_SIGPROF) { + p->p_flag &= ~P_SIGPROF; + ksignal(p, SIGPROF); + } + if (p->p_flag & P_UPCALLPEND) { + p->p_flag &= ~P_UPCALLPEND; + postupcall(lp); + } lwkt_reltoken(&p->p_token); goto recheck; } diff --git a/sys/platform/vkernel64/x86_64/trap.c b/sys/platform/vkernel64/x86_64/trap.c index 9398421738..c7ffa5f46a 100644 --- a/sys/platform/vkernel64/x86_64/trap.c +++ b/sys/platform/vkernel64/x86_64/trap.c @@ -244,12 +244,23 @@ recheck: } /* - * Post any pending upcalls + * Post any pending upcalls. If running a virtual kernel be sure + * to restore the virtual kernel's vmspace before posting the upcall. */ - if (p->p_flag & P_UPCALLPEND) { + if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) { lwkt_gettoken(&p->p_token); - p->p_flag &= ~P_UPCALLPEND; - postupcall(lp); + if (p->p_flag & P_SIGVTALRM) { + p->p_flag &= ~P_SIGVTALRM; + ksignal(p, SIGVTALRM); + } + if (p->p_flag & P_SIGPROF) { + p->p_flag &= ~P_SIGPROF; + ksignal(p, SIGPROF); + } + if (p->p_flag & P_UPCALLPEND) { + p->p_flag &= ~P_UPCALLPEND; + postupcall(lp); + } lwkt_reltoken(&p->p_token); goto recheck; } diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 8ab2ec117a..15ba8ef5d9 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -366,8 +366,8 @@ struct proc { #define P_IDLESWAP 0x400000 /* Swapout was due to idleswap, not load */ #define P_JAILED 0x1000000 /* Process is in jail */ -#define P_UNUSED0 0x2000000 /* need to restore mask before pause */ -#define P_UNUSED1 0x4000000 /* have alternate signal stack */ +#define P_SIGVTALRM 0x2000000 /* signal SIGVTALRM pending due to itimer */ +#define P_SIGPROF 0x4000000 /* signal SIGPROF pending due to itimer */ #define P_INEXEC 0x8000000 /* Process is in execve(). */ #define P_UNUSED1000 0x10000000 #define P_UPCALLWAIT 0x20000000 /* Wait for upcall or signal */ -- 2.41.0