From cfa0efe7ab687949c5d15cfc779f69594def2c15 Mon Sep 17 00:00:00 2001 From: Maxim Sobolev Date: Tue, 25 Jan 2005 21:28:28 +0000 Subject: [PATCH] Split out kernel side of {get,set}itimer(2) into two parts: the first that pops data from the userland and pushes results back and the second which does actual processing. Use the latter to eliminate stackgap in the linux wrappers of those syscalls. MFC after: 2 weeks --- sys/compat/linux/linux_misc.c | 97 ++++++++++++----------------------- sys/kern/kern_time.c | 91 +++++++++++++++++++------------- sys/sys/systm.h | 3 ++ 3 files changed, 92 insertions(+), 99 deletions(-) diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 09219072e89d..cb77fe3afa6b 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -950,97 +950,66 @@ struct l_itimerval { l_timeval it_value; }; +#define B2L_ITIMERVAL(bip, lip) \ + (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ + (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ + (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ + (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; + int linux_setitimer(struct thread *td, struct linux_setitimer_args *uap) { int error; - caddr_t sg; - struct l_itimerval *lp, *lop, ls; - struct itimerval *p = NULL, *op = NULL, s; + struct l_itimerval ls; + struct itimerval aitv, oitv; #ifdef DEBUG if (ldebug(setitimer)) printf(ARGS(setitimer, "%p, %p"), (void *)uap->itv, (void *)uap->oitv); #endif - lp = uap->itv; - if (lp != NULL) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct itimerval)); - uap->itv = (struct l_itimerval *)p; - error = copyin(lp, &ls, sizeof(ls)); - if (error != 0) - return (error); - s.it_interval.tv_sec = ls.it_interval.tv_sec; - s.it_interval.tv_usec = ls.it_interval.tv_usec; - s.it_value.tv_sec = ls.it_value.tv_sec; - s.it_value.tv_usec = ls.it_value.tv_usec; - error = copyout(&s, p, sizeof(s)); - if (error != 0) - return (error); -#ifdef DEBUG - if (ldebug(setitimer)) { - printf("setitimer: value: sec: %ld, usec: %ld\n", - s.it_value.tv_sec, s.it_value.tv_usec); - printf("setitimer: interval: sec: %ld, usec: %ld\n", - s.it_interval.tv_sec, s.it_interval.tv_usec); - } -#endif + + if (uap->itv == NULL) { + uap->itv = uap->oitv; + return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); } - lop = uap->oitv; - if (lop != NULL) { - sg = stackgap_init(); - op = stackgap_alloc(&sg, sizeof(struct itimerval)); - uap->oitv = (struct l_itimerval *)op; - } - error = setitimer(td, (struct setitimer_args *) uap); + + error = copyin(uap->itv, &ls, sizeof(ls)); if (error != 0) return (error); - if (lop != NULL) { - error = copyin(op, &s, sizeof(s)); - if (error != 0) - return (error); - ls.it_interval.tv_sec = s.it_interval.tv_sec; - ls.it_interval.tv_usec = s.it_interval.tv_usec; - ls.it_value.tv_sec = s.it_value.tv_sec; - ls.it_value.tv_usec = s.it_value.tv_usec; - error = copyout(&ls, lop, sizeof(ls)); + B2L_ITIMERVAL(&aitv, &ls); +#ifdef DEBUG + if (ldebug(setitimer)) { + printf("setitimer: value: sec: %ld, usec: %ld\n", + aitv.it_value.tv_sec, aitv.it_value.tv_usec); + printf("setitimer: interval: sec: %ld, usec: %ld\n", + aitv.it_interval.tv_sec, aitv.it_interval.tv_usec); } - return (error); +#endif + error = kern_setitimer(td, uap->which, &aitv, &oitv); + if (error != 0 || uap->oitv == NULL) + return (error); + B2L_ITIMERVAL(&ls, &oitv); + + return (copyout(&ls, uap->oitv, sizeof(ls))); } int linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) { int error; - caddr_t sg; - struct l_itimerval *lp, ls; - struct itimerval *p = NULL, s; + struct l_itimerval ls; + struct itimerval aitv; #ifdef DEBUG if (ldebug(getitimer)) printf(ARGS(getitimer, "%p"), (void *)uap->itv); #endif - lp = uap->itv; - if (lp != NULL) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct itimerval)); - uap->itv = (struct l_itimerval *)p; - } - error = getitimer(td, (struct getitimer_args *) uap); + error = kern_getitimer(td, uap->which, &aitv); if (error != 0) return (error); - if (lp != NULL) { - error = copyin(p, &s, sizeof(s)); - if (error != 0) - return (error); - ls.it_interval.tv_sec = s.it_interval.tv_sec; - ls.it_interval.tv_usec = s.it_interval.tv_usec; - ls.it_value.tv_sec = s.it_value.tv_sec; - ls.it_value.tv_usec = s.it_value.tv_usec; - error = copyout(&ls, lp, sizeof(ls)); - } - return (error); + B2L_ITIMERVAL(&ls, &aitv); + return (copyout(&ls, uap->itv, sizeof(ls))); } #ifndef __alpha__ diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 4e6fe7f5ff11..c05732df776a 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -437,14 +437,25 @@ struct getitimer_args { int getitimer(struct thread *td, struct getitimer_args *uap) { - struct proc *p = td->td_proc; - struct timeval ctv; + int error; struct itimerval aitv; - if (uap->which > ITIMER_PROF) + error = kern_getitimer(td, uap->which, &aitv); + if (error != 0) + return (error); + return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); +} + +int +kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) +{ + struct proc *p = td->td_proc; + struct timeval ctv; + + if (which > ITIMER_PROF) return (EINVAL); - if (uap->which == ITIMER_REAL) { + if (which == ITIMER_REAL) { /* * Convert from absolute to relative time in .it_value * part of real time timer. If time for real time timer @@ -452,21 +463,21 @@ getitimer(struct thread *td, struct getitimer_args *uap) * current time and time for the timer to go off. */ PROC_LOCK(p); - aitv = p->p_realtimer; + *aitv = p->p_realtimer; PROC_UNLOCK(p); - if (timevalisset(&aitv.it_value)) { + if (timevalisset(&aitv->it_value)) { getmicrouptime(&ctv); - if (timevalcmp(&aitv.it_value, &ctv, <)) - timevalclear(&aitv.it_value); + if (timevalcmp(&aitv->it_value, &ctv, <)) + timevalclear(&aitv->it_value); else - timevalsub(&aitv.it_value, &ctv); + timevalsub(&aitv->it_value, &ctv); } } else { mtx_lock_spin(&sched_lock); - aitv = p->p_stats->p_timer[uap->which]; + *aitv = p->p_stats->p_timer[which]; mtx_unlock_spin(&sched_lock); } - return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); + return (0); } #ifndef _SYS_SYSPROTO_H_ @@ -475,61 +486,71 @@ struct setitimer_args { struct itimerval *itv, *oitv; }; #endif + /* * MPSAFE */ int setitimer(struct thread *td, struct setitimer_args *uap) { - struct proc *p = td->td_proc; - struct itimerval aitv, oitv; - struct timeval ctv; int error; + struct itimerval aitv, oitv; if (uap->itv == NULL) { uap->itv = uap->oitv; return (getitimer(td, (struct getitimer_args *)uap)); } - if (uap->which > ITIMER_PROF) - return (EINVAL); if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval)))) return (error); - if (itimerfix(&aitv.it_value)) + error = kern_setitimer(td, uap->which, &aitv, &oitv); + if (error != 0 || uap->oitv == NULL) + return (error); + + return (copyout(&oitv, uap->oitv, sizeof(struct itimerval))); +} + +int +kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, struct itimerval *oitv) +{ + struct proc *p = td->td_proc; + struct timeval ctv; + + if (which > ITIMER_PROF) return (EINVAL); - if (!timevalisset(&aitv.it_value)) - timevalclear(&aitv.it_interval); - else if (itimerfix(&aitv.it_interval)) + if (itimerfix(&aitv->it_value)) + return (EINVAL); + if (!timevalisset(&aitv->it_value)) + timevalclear(&aitv->it_interval); + else if (itimerfix(&aitv->it_interval)) return (EINVAL); - if (uap->which == ITIMER_REAL) { + if (which == ITIMER_REAL) { PROC_LOCK(p); if (timevalisset(&p->p_realtimer.it_value)) callout_stop(&p->p_itcallout); getmicrouptime(&ctv); - if (timevalisset(&aitv.it_value)) { - callout_reset(&p->p_itcallout, tvtohz(&aitv.it_value), + if (timevalisset(&aitv->it_value)) { + callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value), realitexpire, p); - timevaladd(&aitv.it_value, &ctv); + timevaladd(&aitv->it_value, &ctv); } - oitv = p->p_realtimer; - p->p_realtimer = aitv; + *oitv = p->p_realtimer; + p->p_realtimer = *aitv; PROC_UNLOCK(p); - if (timevalisset(&oitv.it_value)) { - if (timevalcmp(&oitv.it_value, &ctv, <)) - timevalclear(&oitv.it_value); + if (timevalisset(&oitv->it_value)) { + if (timevalcmp(&oitv->it_value, &ctv, <)) + timevalclear(&oitv->it_value); else - timevalsub(&oitv.it_value, &ctv); + timevalsub(&oitv->it_value, &ctv); } } else { mtx_lock_spin(&sched_lock); - oitv = p->p_stats->p_timer[uap->which]; - p->p_stats->p_timer[uap->which] = aitv; + *oitv = p->p_stats->p_timer[which]; + p->p_stats->p_timer[which] = *aitv; mtx_unlock_spin(&sched_lock); } - if (uap->oitv == NULL) - return (0); - return (copyout(&oitv, uap->oitv, sizeof(struct itimerval))); + return (0); } /* diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 36a841669d92..4b7dfd9de7cd 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -115,6 +115,7 @@ struct tty; struct ucred; struct uio; struct _jmp_buf; +struct itimerval; int setjmp(struct _jmp_buf *); void longjmp(struct _jmp_buf *, int) __dead2; @@ -199,6 +200,8 @@ int suword32(void *base, int32_t word); int suword64(void *base, int64_t word); intptr_t casuptr(intptr_t *p, intptr_t old, intptr_t new); +int kern_getitimer(struct thread *, u_int, struct itimerval *); +int kern_setitimer(struct thread *, u_int, struct itimerval *, struct itimerval *); void realitexpire(void *); void hardclock(struct clockframe *frame);