Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/kern_resource.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/kern_resource.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.103 retrieving revision 1.103.4.3 diff -u -p -r1.103 -r1.103.4.3 --- src/sys/kern/kern_resource.c 2006/07/30 17:38:19 1.103 +++ src/sys/kern/kern_resource.c 2006/10/24 21:10:21 1.103.4.3 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_resource.c,v 1.103 2006/07/30 17:38:19 elad Exp $ */ +/* $NetBSD: kern_resource.c,v 1.103.4.3 2006/10/24 21:10:21 ad Exp $ */ /*- * Copyright (c) 1982, 1986, 1991, 1993 @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.103 2006/07/30 17:38:19 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.103.4.3 2006/10/24 21:10:21 ad Exp $"); #include #include @@ -82,43 +82,50 @@ sys_getpriority(struct lwp *l, void *v, } */ *uap = v; struct proc *curp = l->l_proc, *p; int low = NZERO + PRIO_MAX + 1; + int who = SCARG(uap, who); switch (SCARG(uap, which)) { case PRIO_PROCESS: - if (SCARG(uap, who) == 0) + if (who == 0) p = curp; else - p = pfind(SCARG(uap, who)); - if (p == 0) - break; - low = p->p_nice; + p = p_find(who, 0); + if (p != NULL) + low = p->p_nice; + if (who != 0) + rw_exit(&proclist_lock); break; case PRIO_PGRP: { struct pgrp *pg; - if (SCARG(uap, who) == 0) + rw_enter(&proclist_lock, RW_READER); + if (who == 0) pg = curp->p_pgrp; - else if ((pg = pgfind(SCARG(uap, who))) == NULL) + else if ((pg = pg_find(who, PFIND_LOCKED | PFIND_UNLOCK_FAIL)) + == NULL) break; LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (p->p_nice < low) low = p->p_nice; } + rw_exit(&proclist_lock); break; } case PRIO_USER: - if (SCARG(uap, who) == 0) - SCARG(uap, who) = kauth_cred_geteuid(l->l_cred); - proclist_lock_read(); + if (who == 0) + who = (int)kauth_cred_geteuid(l->l_cred); + rw_enter(&proclist_lock, RW_READER); PROCLIST_FOREACH(p, &allproc) { + mutex_enter(&p->p_crmutex); if (kauth_cred_geteuid(p->p_cred) == - (uid_t) SCARG(uap, who) && p->p_nice < low) + (uid_t)who && p->p_nice < low) low = p->p_nice; + mutex_exit(&p->p_crmutex); } - proclist_unlock_read(); + rw_exit(&proclist_lock); break; default: @@ -141,46 +148,57 @@ sys_setpriority(struct lwp *l, void *v, } */ *uap = v; struct proc *curp = l->l_proc, *p; int found = 0, error = 0; + int who = SCARG(uap, who); switch (SCARG(uap, which)) { case PRIO_PROCESS: - if (SCARG(uap, who) == 0) + if (who == 0) p = curp; else - p = pfind(SCARG(uap, who)); - if (p == 0) - break; - error = donice(l, p, SCARG(uap, prio)); + p = p_find(who, 0); + if (p != 0) { + mutex_enter(&p->p_crmutex); + error = donice(l, p, SCARG(uap, prio)); + mutex_exit(&p->p_crmutex); + } + if (who != 0) + rw_exit(&proclist_lock); found++; break; case PRIO_PGRP: { struct pgrp *pg; - if (SCARG(uap, who) == 0) + rw_enter(&proclist_lock, RW_READER); + if (who == 0) pg = curp->p_pgrp; - else if ((pg = pgfind(SCARG(uap, who))) == NULL) + else if ((pg = pg_find(who, PFIND_LOCKED | PFIND_UNLOCK_FAIL)) == NULL) break; LIST_FOREACH(p, &pg->pg_members, p_pglist) { + mutex_enter(&p->p_crmutex); error = donice(l, p, SCARG(uap, prio)); + mutex_exit(&p->p_crmutex); found++; } + rw_exit(&proclist_lock); break; } case PRIO_USER: - if (SCARG(uap, who) == 0) - SCARG(uap, who) = kauth_cred_geteuid(l->l_cred); - proclist_lock_read(); + if (who == 0) + who = (int)kauth_cred_geteuid(l->l_cred); + rw_enter(&proclist_lock, RW_READER); PROCLIST_FOREACH(p, &allproc) { + mutex_enter(&p->p_crmutex); if (kauth_cred_geteuid(p->p_cred) == (uid_t)SCARG(uap, who)) { error = donice(l, p, SCARG(uap, prio)); found++; } + mutex_exit(&p->p_crmutex); } - proclist_unlock_read(); + rw_exit(&proclist_lock); break; default: @@ -191,11 +209,18 @@ sys_setpriority(struct lwp *l, void *v, return (error); } +/* + * Renice a process. + * + * Call with the target process' credentials locked. + */ int donice(struct lwp *l, struct proc *chgp, int n) { kauth_cred_t cred = l->l_cred; - int s; + int onice; + + LOCK_ASSERT(mutex_owned(&chgp->p_crmutex)); if (kauth_cred_geteuid(cred) && kauth_cred_getuid(cred) && kauth_cred_geteuid(cred) != kauth_cred_geteuid(chgp->p_cred) && @@ -206,13 +231,19 @@ donice(struct lwp *l, struct proc *chgp, if (n < PRIO_MIN) n = PRIO_MIN; n += NZERO; - if (n < chgp->p_nice && kauth_authorize_generic(cred, + + again: + if (n < (onice = chgp->p_nice) && kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, &l->l_acflag)) return (EACCES); + mutex_enter(&chgp->p_smutex); + if (onice != chgp->p_nice) { + mutex_exit(&chgp->p_smutex); + goto again; + } chgp->p_nice = n; - SCHED_LOCK(s); (void)resetprocpriority(chgp); - SCHED_UNLOCK(s); + mutex_exit(&chgp->p_smutex); return (0); } @@ -371,7 +402,7 @@ sys_getrlimit(struct lwp *l, void *v, re */ void calcru(struct proc *p, struct timeval *up, struct timeval *sp, - struct timeval *ip) + struct timeval *ip, struct timeval *rp) { u_quad_t u, st, ut, it, tot; unsigned long sec; @@ -380,15 +411,20 @@ calcru(struct proc *p, struct timeval *u struct timeval tv; struct lwp *l; + LOCK_ASSERT(mutex_owned(&p->p_smutex)); + s = splstatclock(); st = p->p_sticks; ut = p->p_uticks; it = p->p_iticks; splx(s); - sec = p->p_rtime.tv_sec; - usec = p->p_rtime.tv_usec; + sec = 0; + usec = 0; LIST_FOREACH(l, &p->p_lwps, l_sibling) { + lwp_lock(l); + sec += l->l_rtime.tv_sec; + usec += l->l_rtime.tv_usec; if (l->l_stat == LSONPROC) { struct schedstate_percpu *spc; @@ -406,6 +442,7 @@ calcru(struct proc *p, struct timeval *u sec += tv.tv_sec - spc->spc_runtime.tv_sec; usec += tv.tv_usec - spc->spc_runtime.tv_usec; } + lwp_unlock(l); } tot = st + ut + it; @@ -418,16 +455,34 @@ calcru(struct proc *p, struct timeval *u st = (u * st) / tot; ut = (u * ut) / tot; } - sp->tv_sec = st / 1000000; - sp->tv_usec = st % 1000000; - up->tv_sec = ut / 1000000; - up->tv_usec = ut % 1000000; + if (sp != NULL) { + if (tot == 0) { + /* No ticks, so can't use to share time out, split 50-50 */ + st = u / 2; + } else + st = (u * st) / tot; + sp->tv_sec = st / 1000000; + sp->tv_usec = st % 1000000; + } + if (up != NULL) { + if (tot == 0) { + /* No ticks, so can't use to share time out, split 50-50 */ + ut = u / 2; + } else + ut = (u * ut) / tot; + up->tv_sec = ut / 1000000; + up->tv_usec = ut % 1000000; + } if (ip != NULL) { if (it != 0) it = (u * it) / tot; ip->tv_sec = it / 1000000; ip->tv_usec = it % 1000000; } + if (rp != NULL) { + rp->tv_sec = sec; + rp->tv_usec = usec; + } } /* ARGSUSED */ @@ -445,7 +500,9 @@ sys_getrusage(struct lwp *l, void *v, re case RUSAGE_SELF: rup = &p->p_stats->p_ru; - calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); + mutex_enter(&p->p_smutex); + calcru(p, &rup->ru_utime, &rup->ru_stime, NULL, NULL); + mutex_exit(&p->p_smutex); break; case RUSAGE_CHILDREN: