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