[BACK]Return to kern_resource.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_resource.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: kern_resource.c,v 1.32 2007/04/12 22:14:15 tedu Exp $ */
                      2: /*     $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias Exp $      */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1982, 1986, 1991, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  * (c) UNIX System Laboratories, Inc.
                      8:  * All or some portions of this file are derived from material licensed
                      9:  * to the University of California by American Telephone and Telegraph
                     10:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     11:  * the permission of UNIX System Laboratories, Inc.
                     12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
                     21:  * 3. Neither the name of the University nor the names of its contributors
                     22:  *    may be used to endorse or promote products derived from this software
                     23:  *    without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     28:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     29:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     30:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     31:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     33:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     34:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     35:  * SUCH DAMAGE.
                     36:  *
                     37:  *     @(#)kern_resource.c     8.5 (Berkeley) 1/21/94
                     38:  */
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/kernel.h>
                     43: #include <sys/file.h>
                     44: #include <sys/resourcevar.h>
                     45: #include <sys/pool.h>
                     46: #include <sys/proc.h>
                     47: #include <sys/sched.h>
                     48:
                     49: #include <sys/mount.h>
                     50: #include <sys/syscallargs.h>
                     51:
                     52: #include <uvm/uvm_extern.h>
                     53:
                     54: /*
                     55:  * Patchable maximum data and stack limits.
                     56:  */
                     57: rlim_t maxdmap = MAXDSIZ;
                     58: rlim_t maxsmap = MAXSSIZ;
                     59:
                     60: /*
                     61:  * Resource controls and accounting.
                     62:  */
                     63:
                     64: int
                     65: sys_getpriority(struct proc *curp, void *v, register_t *retval)
                     66: {
                     67:        struct sys_getpriority_args /* {
                     68:                syscallarg(int) which;
                     69:                syscallarg(id_t) who;
                     70:        } */ *uap = v;
                     71:        struct proc *p;
                     72:        int low = NZERO + PRIO_MAX + 1;
                     73:
                     74:        switch (SCARG(uap, which)) {
                     75:
                     76:        case PRIO_PROCESS:
                     77:                if (SCARG(uap, who) == 0)
                     78:                        p = curp;
                     79:                else
                     80:                        p = pfind(SCARG(uap, who));
                     81:                if (p == 0)
                     82:                        break;
                     83:                low = p->p_nice;
                     84:                break;
                     85:
                     86:        case PRIO_PGRP: {
                     87:                struct pgrp *pg;
                     88:
                     89:                if (SCARG(uap, who) == 0)
                     90:                        pg = curp->p_pgrp;
                     91:                else if ((pg = pgfind(SCARG(uap, who))) == NULL)
                     92:                        break;
                     93:                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                     94:                        if (p->p_nice < low)
                     95:                                low = p->p_nice;
                     96:                }
                     97:                break;
                     98:        }
                     99:
                    100:        case PRIO_USER:
                    101:                if (SCARG(uap, who) == 0)
                    102:                        SCARG(uap, who) = curp->p_ucred->cr_uid;
                    103:                for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list))
                    104:                        if (p->p_ucred->cr_uid == SCARG(uap, who) &&
                    105:                            p->p_nice < low)
                    106:                                low = p->p_nice;
                    107:                break;
                    108:
                    109:        default:
                    110:                return (EINVAL);
                    111:        }
                    112:        if (low == NZERO + PRIO_MAX + 1)
                    113:                return (ESRCH);
                    114:        *retval = low - NZERO;
                    115:        return (0);
                    116: }
                    117:
                    118: /* ARGSUSED */
                    119: int
                    120: sys_setpriority(struct proc *curp, void *v, register_t *retval)
                    121: {
                    122:        struct sys_setpriority_args /* {
                    123:                syscallarg(int) which;
                    124:                syscallarg(id_t) who;
                    125:                syscallarg(int) prio;
                    126:        } */ *uap = v;
                    127:        struct proc *p;
                    128:        int found = 0, error = 0;
                    129:
                    130:        switch (SCARG(uap, which)) {
                    131:
                    132:        case PRIO_PROCESS:
                    133:                if (SCARG(uap, who) == 0)
                    134:                        p = curp;
                    135:                else
                    136:                        p = pfind(SCARG(uap, who));
                    137:                if (p == 0)
                    138:                        break;
                    139:                error = donice(curp, p, SCARG(uap, prio));
                    140:                found++;
                    141:                break;
                    142:
                    143:        case PRIO_PGRP: {
                    144:                struct pgrp *pg;
                    145:
                    146:                if (SCARG(uap, who) == 0)
                    147:                        pg = curp->p_pgrp;
                    148:                else if ((pg = pgfind(SCARG(uap, who))) == NULL)
                    149:                        break;
                    150:                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                    151:                        error = donice(curp, p, SCARG(uap, prio));
                    152:                        found++;
                    153:                }
                    154:                break;
                    155:        }
                    156:
                    157:        case PRIO_USER:
                    158:                if (SCARG(uap, who) == 0)
                    159:                        SCARG(uap, who) = curp->p_ucred->cr_uid;
                    160:                for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list))
                    161:                        if (p->p_ucred->cr_uid == SCARG(uap, who)) {
                    162:                                error = donice(curp, p, SCARG(uap, prio));
                    163:                                found++;
                    164:                        }
                    165:                break;
                    166:
                    167:        default:
                    168:                return (EINVAL);
                    169:        }
                    170:        if (found == 0)
                    171:                return (ESRCH);
                    172:        return (error);
                    173: }
                    174:
                    175: int
                    176: donice(struct proc *curp, struct proc *chgp, int n)
                    177: {
                    178:        struct pcred *pcred = curp->p_cred;
                    179:        int s;
                    180:
                    181:        if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
                    182:            pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
                    183:            pcred->p_ruid != chgp->p_ucred->cr_uid)
                    184:                return (EPERM);
                    185:        if (n > PRIO_MAX)
                    186:                n = PRIO_MAX;
                    187:        if (n < PRIO_MIN)
                    188:                n = PRIO_MIN;
                    189:        n += NZERO;
                    190:        if (n < chgp->p_nice && suser(curp, 0))
                    191:                return (EACCES);
                    192:        chgp->p_nice = n;
                    193:        SCHED_LOCK(s);
                    194:        (void)resetpriority(chgp);
                    195:        SCHED_UNLOCK(s);
                    196:        return (0);
                    197: }
                    198:
                    199: /* ARGSUSED */
                    200: int
                    201: sys_setrlimit(struct proc *p, void *v, register_t *retval)
                    202: {
                    203:        struct sys_setrlimit_args /* {
                    204:                syscallarg(int) which;
                    205:                syscallarg(const struct rlimit *) rlp;
                    206:        } */ *uap = v;
                    207:        struct rlimit alim;
                    208:        int error;
                    209:
                    210:        error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim,
                    211:                       sizeof (struct rlimit));
                    212:        if (error)
                    213:                return (error);
                    214:        return (dosetrlimit(p, SCARG(uap, which), &alim));
                    215: }
                    216:
                    217: int
                    218: dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
                    219: {
                    220:        struct rlimit *alimp;
                    221:        rlim_t maxlim;
                    222:        int error;
                    223:
                    224:        if (which >= RLIM_NLIMITS)
                    225:                return (EINVAL);
                    226:
                    227:        alimp = &p->p_rlimit[which];
                    228:        if (limp->rlim_cur > alimp->rlim_max ||
                    229:            limp->rlim_max > alimp->rlim_max)
                    230:                if ((error = suser(p, 0)) != 0)
                    231:                        return (error);
                    232:        if (p->p_p->ps_limit->p_refcnt > 1 &&
                    233:            (p->p_p->ps_limit->p_lflags & PL_SHAREMOD) == 0) {
                    234:                p->p_p->ps_limit->p_refcnt--;
                    235:                p->p_p->ps_limit = limcopy(p->p_p->ps_limit);
                    236:                alimp = &p->p_rlimit[which];
                    237:        }
                    238:
                    239:        switch (which) {
                    240:        case RLIMIT_DATA:
                    241:                maxlim = maxdmap;
                    242:                break;
                    243:        case RLIMIT_STACK:
                    244:                maxlim = maxsmap;
                    245:                break;
                    246:        case RLIMIT_NOFILE:
                    247:                maxlim = maxfiles;
                    248:                break;
                    249:        case RLIMIT_NPROC:
                    250:                maxlim = maxproc;
                    251:                break;
                    252:        default:
                    253:                maxlim = RLIM_INFINITY;
                    254:                break;
                    255:        }
                    256:
                    257:        if (limp->rlim_max > maxlim)
                    258:                limp->rlim_max = maxlim;
                    259:        if (limp->rlim_cur > limp->rlim_max)
                    260:                limp->rlim_cur = limp->rlim_max;
                    261:
                    262:        if (which == RLIMIT_STACK) {
                    263:                /*
                    264:                 * Stack is allocated to the max at exec time with only
                    265:                 * "rlim_cur" bytes accessible.  If stack limit is going
                    266:                 * up make more accessible, if going down make inaccessible.
                    267:                 */
                    268:                if (limp->rlim_cur != alimp->rlim_cur) {
                    269:                        vaddr_t addr;
                    270:                        vsize_t size;
                    271:                        vm_prot_t prot;
                    272:
                    273:                        if (limp->rlim_cur > alimp->rlim_cur) {
                    274:                                prot = VM_PROT_READ|VM_PROT_WRITE;
                    275:                                size = limp->rlim_cur - alimp->rlim_cur;
                    276: #ifdef MACHINE_STACK_GROWS_UP
                    277:                                addr = USRSTACK + alimp->rlim_cur;
                    278: #else
                    279:                                addr = USRSTACK - limp->rlim_cur;
                    280: #endif
                    281:                        } else {
                    282:                                prot = VM_PROT_NONE;
                    283:                                size = alimp->rlim_cur - limp->rlim_cur;
                    284: #ifdef MACHINE_STACK_GROWS_UP
                    285:                                addr = USRSTACK + limp->rlim_cur;
                    286: #else
                    287:                                addr = USRSTACK - alimp->rlim_cur;
                    288: #endif
                    289:                        }
                    290:                        addr = trunc_page(addr);
                    291:                        size = round_page(size);
                    292:                        (void) uvm_map_protect(&p->p_vmspace->vm_map,
                    293:                                              addr, addr+size, prot, FALSE);
                    294:                }
                    295:        }
                    296:
                    297:        *alimp = *limp;
                    298:        return (0);
                    299: }
                    300:
                    301: /* ARGSUSED */
                    302: int
                    303: sys_getrlimit(struct proc *p, void *v, register_t *retval)
                    304: {
                    305:        struct sys_getrlimit_args /* {
                    306:                syscallarg(int) which;
                    307:                syscallarg(struct rlimit *) rlp;
                    308:        } */ *uap = v;
                    309:
                    310:        if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS)
                    311:                return (EINVAL);
                    312:        return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)],
                    313:            (caddr_t)SCARG(uap, rlp), sizeof (struct rlimit)));
                    314: }
                    315:
                    316: /*
                    317:  * Transform the running time and tick information in proc p into user,
                    318:  * system, and interrupt time usage.
                    319:  */
                    320: void
                    321: calcru(struct proc *p, struct timeval *up, struct timeval *sp,
                    322:     struct timeval *ip)
                    323: {
                    324:        u_quad_t st, ut, it;
                    325:        int freq;
                    326:        int s;
                    327:
                    328:        s = splstatclock();
                    329:        st = p->p_sticks;
                    330:        ut = p->p_uticks;
                    331:        it = p->p_iticks;
                    332:        splx(s);
                    333:
                    334:        if (st + ut + it == 0) {
                    335:                timerclear(up);
                    336:                timerclear(sp);
                    337:                if (ip != NULL)
                    338:                        timerclear(ip);
                    339:                return;
                    340:        }
                    341:
                    342:        freq = stathz ? stathz : hz;
                    343:
                    344:        st = st * 1000000 / freq;
                    345:        sp->tv_sec = st / 1000000;
                    346:        sp->tv_usec = st % 1000000;
                    347:        ut = ut * 1000000 / freq;
                    348:        up->tv_sec = ut / 1000000;
                    349:        up->tv_usec = ut % 1000000;
                    350:        if (ip != NULL) {
                    351:                it = it * 1000000 / freq;
                    352:                ip->tv_sec = it / 1000000;
                    353:                ip->tv_usec = it % 1000000;
                    354:        }
                    355: }
                    356:
                    357: /* ARGSUSED */
                    358: int
                    359: sys_getrusage(struct proc *p, void *v, register_t *retval)
                    360: {
                    361:        struct sys_getrusage_args /* {
                    362:                syscallarg(int) who;
                    363:                syscallarg(struct rusage *) rusage;
                    364:        } */ *uap = v;
                    365:        struct rusage *rup;
                    366:
                    367:        switch (SCARG(uap, who)) {
                    368:
                    369:        case RUSAGE_SELF:
                    370:                rup = &p->p_stats->p_ru;
                    371:                calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
                    372:                break;
                    373:
                    374:        case RUSAGE_CHILDREN:
                    375:                rup = &p->p_stats->p_cru;
                    376:                break;
                    377:
                    378:        default:
                    379:                return (EINVAL);
                    380:        }
                    381:        return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage),
                    382:            sizeof (struct rusage)));
                    383: }
                    384:
                    385: void
                    386: ruadd(struct rusage *ru, struct rusage *ru2)
                    387: {
                    388:        long *ip, *ip2;
                    389:        int i;
                    390:
                    391:        timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
                    392:        timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
                    393:        if (ru->ru_maxrss < ru2->ru_maxrss)
                    394:                ru->ru_maxrss = ru2->ru_maxrss;
                    395:        ip = &ru->ru_first; ip2 = &ru2->ru_first;
                    396:        for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
                    397:                *ip++ += *ip2++;
                    398: }
                    399:
                    400: struct pool plimit_pool;
                    401:
                    402: /*
                    403:  * Make a copy of the plimit structure.
                    404:  * We share these structures copy-on-write after fork,
                    405:  * and copy when a limit is changed.
                    406:  */
                    407: struct plimit *
                    408: limcopy(struct plimit *lim)
                    409: {
                    410:        struct plimit *newlim;
                    411:        static int initialized;
                    412:
                    413:        if (!initialized) {
                    414:                pool_init(&plimit_pool, sizeof(struct plimit), 0, 0, 0,
                    415:                    "plimitpl", &pool_allocator_nointr);
                    416:                initialized = 1;
                    417:        }
                    418:
                    419:        newlim = pool_get(&plimit_pool, PR_WAITOK);
                    420:        bcopy(lim->pl_rlimit, newlim->pl_rlimit,
                    421:            sizeof(struct rlimit) * RLIM_NLIMITS);
                    422:        newlim->p_lflags = 0;
                    423:        newlim->p_refcnt = 1;
                    424:        return (newlim);
                    425: }
                    426:
                    427: void
                    428: limfree(struct plimit *lim)
                    429: {
                    430:        if (--lim->p_refcnt > 0)
                    431:                return;
                    432:        pool_put(&plimit_pool, lim);
                    433: }

CVSweb