]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_resource.c
This commit was generated by cvs2svn to compensate for changes in r53809,
[FreeBSD/FreeBSD.git] / sys / kern / kern_resource.c
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  * $FreeBSD$
40  */
41
42 #include "opt_compat.h"
43 #include "opt_rlimit.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/sysproto.h>
48 #include <sys/file.h>
49 #include <sys/resourcevar.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <sys/lock.h>
56 #include <vm/pmap.h>
57 #include <vm/vm_map.h>
58
59 static int donice __P((struct proc *curp, struct proc *chgp, int n));
60 /* dosetrlimit non-static:  Needed by SysVR4 emulator */
61 int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
62
63 /*
64  * Resource controls and accounting.
65  */
66
67 #ifndef _SYS_SYSPROTO_H_
68 struct getpriority_args {
69         int     which;
70         int     who;
71 };
72 #endif
73 int
74 getpriority(curp, uap)
75         struct proc *curp;
76         register struct getpriority_args *uap;
77 {
78         register struct proc *p;
79         register int low = PRIO_MAX + 1;
80
81         switch (uap->which) {
82
83         case PRIO_PROCESS:
84                 if (uap->who == 0)
85                         p = curp;
86                 else
87                         p = pfind(uap->who);
88                 if (p == 0)
89                         break;
90                 low = p->p_nice;
91                 break;
92
93         case PRIO_PGRP: {
94                 register struct pgrp *pg;
95
96                 if (uap->who == 0)
97                         pg = curp->p_pgrp;
98                 else if ((pg = pgfind(uap->who)) == NULL)
99                         break;
100                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
101                         if (p->p_nice < low)
102                                 low = p->p_nice;
103                 }
104                 break;
105         }
106
107         case PRIO_USER:
108                 if (uap->who == 0)
109                         uap->who = curp->p_ucred->cr_uid;
110                 LIST_FOREACH(p, &allproc, p_list)
111                         if (p->p_ucred->cr_uid == uap->who &&
112                             p->p_nice < low)
113                                 low = p->p_nice;
114                 break;
115
116         default:
117                 return (EINVAL);
118         }
119         if (low == PRIO_MAX + 1)
120                 return (ESRCH);
121         curp->p_retval[0] = low;
122         return (0);
123 }
124
125 #ifndef _SYS_SYSPROTO_H_
126 struct setpriority_args {
127         int     which;
128         int     who;
129         int     prio;
130 };
131 #endif
132 /* ARGSUSED */
133 int
134 setpriority(curp, uap)
135         struct proc *curp;
136         register struct setpriority_args *uap;
137 {
138         register struct proc *p;
139         int found = 0, error = 0;
140
141         switch (uap->which) {
142
143         case PRIO_PROCESS:
144                 if (uap->who == 0)
145                         p = curp;
146                 else
147                         p = pfind(uap->who);
148                 if (p == 0)
149                         break;
150                 error = donice(curp, p, uap->prio);
151                 found++;
152                 break;
153
154         case PRIO_PGRP: {
155                 register struct pgrp *pg;
156
157                 if (uap->who == 0)
158                         pg = curp->p_pgrp;
159                 else if ((pg = pgfind(uap->who)) == NULL)
160                         break;
161                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
162                         error = donice(curp, p, uap->prio);
163                         found++;
164                 }
165                 break;
166         }
167
168         case PRIO_USER:
169                 if (uap->who == 0)
170                         uap->who = curp->p_ucred->cr_uid;
171                 LIST_FOREACH(p, &allproc, p_list)
172                         if (p->p_ucred->cr_uid == uap->who) {
173                                 error = donice(curp, p, uap->prio);
174                                 found++;
175                         }
176                 break;
177
178         default:
179                 return (EINVAL);
180         }
181         if (found == 0)
182                 return (ESRCH);
183         return (error);
184 }
185
186 static int
187 donice(curp, chgp, n)
188         register struct proc *curp, *chgp;
189         register int n;
190 {
191         register struct pcred *pcred = curp->p_cred;
192
193         if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
194             pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
195             pcred->p_ruid != chgp->p_ucred->cr_uid)
196                 return (EPERM);
197         if (n > PRIO_MAX)
198                 n = PRIO_MAX;
199         if (n < PRIO_MIN)
200                 n = PRIO_MIN;
201         if (n < chgp->p_nice && suser(curp))
202                 return (EACCES);
203         chgp->p_nice = n;
204         (void)resetpriority(chgp);
205         return (0);
206 }
207
208 /* rtprio system call */
209 #ifndef _SYS_SYSPROTO_H_
210 struct rtprio_args {
211         int             function;
212         pid_t           pid;
213         struct rtprio   *rtp;
214 };
215 #endif
216
217 /*
218  * Set realtime priority
219  */
220
221 /* ARGSUSED */
222 int
223 rtprio(curp, uap)
224         struct proc *curp;
225         register struct rtprio_args *uap;
226 {
227         register struct proc *p;
228         register struct pcred *pcred = curp->p_cred;
229         struct rtprio rtp;
230         int error;
231
232         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
233         if (error)
234                 return (error);
235
236         if (uap->pid == 0)
237                 p = curp;
238         else
239                 p = pfind(uap->pid);
240
241         if (p == 0)
242                 return (ESRCH);
243
244         switch (uap->function) {
245         case RTP_LOOKUP:
246                 return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
247         case RTP_SET:
248                 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
249                     pcred->pc_ucred->cr_uid != p->p_ucred->cr_uid &&
250                     pcred->p_ruid != p->p_ucred->cr_uid)
251                         return (EPERM);
252                 /* disallow setting rtprio in most cases if not superuser */
253                 if (suser(curp)) {
254                         /* can't set someone else's */
255                         if (uap->pid)
256                                 return (EPERM);
257                         /* can't set realtime priority */
258 /*
259  * Realtime priority has to be restricted for reasons which should be
260  * obvious. However, for idle priority, there is a potential for
261  * system deadlock if an idleprio process gains a lock on a resource
262  * that other processes need (and the idleprio process can't run
263  * due to a CPU-bound normal process). Fix me! XXX
264  */
265 #if 0
266                         if (RTP_PRIO_IS_REALTIME(rtp.type))
267 #endif
268                         if (rtp.type != RTP_PRIO_NORMAL)
269                                 return (EPERM);
270                 }
271                 switch (rtp.type) {
272 #ifdef RTP_PRIO_FIFO
273                 case RTP_PRIO_FIFO:
274 #endif
275                 case RTP_PRIO_REALTIME:
276                 case RTP_PRIO_NORMAL:
277                 case RTP_PRIO_IDLE:
278                         if (rtp.prio > RTP_PRIO_MAX)
279                                 return (EINVAL);
280                         p->p_rtprio = rtp;
281                         return (0);
282                 default:
283                         return (EINVAL);
284                 }
285
286         default:
287                 return (EINVAL);
288         }
289 }
290
291 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
292 #ifndef _SYS_SYSPROTO_H_
293 struct osetrlimit_args {
294         u_int   which;
295         struct  orlimit *rlp;
296 };
297 #endif
298 /* ARGSUSED */
299 int
300 osetrlimit(p, uap)
301         struct proc *p;
302         register struct osetrlimit_args *uap;
303 {
304         struct orlimit olim;
305         struct rlimit lim;
306         int error;
307
308         if ((error =
309             copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
310                 return (error);
311         lim.rlim_cur = olim.rlim_cur;
312         lim.rlim_max = olim.rlim_max;
313         return (dosetrlimit(p, uap->which, &lim));
314 }
315
316 #ifndef _SYS_SYSPROTO_H_
317 struct ogetrlimit_args {
318         u_int   which;
319         struct  orlimit *rlp;
320 };
321 #endif
322 /* ARGSUSED */
323 int
324 ogetrlimit(p, uap)
325         struct proc *p;
326         register struct ogetrlimit_args *uap;
327 {
328         struct orlimit olim;
329
330         if (uap->which >= RLIM_NLIMITS)
331                 return (EINVAL);
332         olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
333         if (olim.rlim_cur == -1)
334                 olim.rlim_cur = 0x7fffffff;
335         olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
336         if (olim.rlim_max == -1)
337                 olim.rlim_max = 0x7fffffff;
338         return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
339 }
340 #endif /* COMPAT_43 || COMPAT_SUNOS */
341
342 #ifndef _SYS_SYSPROTO_H_
343 struct __setrlimit_args {
344         u_int   which;
345         struct  rlimit *rlp;
346 };
347 #endif
348 /* ARGSUSED */
349 int
350 setrlimit(p, uap)
351         struct proc *p;
352         register struct __setrlimit_args *uap;
353 {
354         struct rlimit alim;
355         int error;
356
357         if ((error =
358             copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
359                 return (error);
360         return (dosetrlimit(p, uap->which, &alim));
361 }
362
363 int
364 dosetrlimit(p, which, limp)
365         struct proc *p;
366         u_int which;
367         struct rlimit *limp;
368 {
369         register struct rlimit *alimp;
370         int error;
371
372         if (which >= RLIM_NLIMITS)
373                 return (EINVAL);
374         alimp = &p->p_rlimit[which];
375
376         /*
377          * Preserve historical bugs by treating negative limits as unsigned.
378          */
379         if (limp->rlim_cur < 0)
380                 limp->rlim_cur = RLIM_INFINITY;
381         if (limp->rlim_max < 0)
382                 limp->rlim_max = RLIM_INFINITY;
383
384         if (limp->rlim_cur > alimp->rlim_max ||
385             limp->rlim_max > alimp->rlim_max)
386                 if ((error = suser_xxx(0, p, PRISON_ROOT)))
387                         return (error);
388         if (limp->rlim_cur > limp->rlim_max)
389                 limp->rlim_cur = limp->rlim_max;
390         if (p->p_limit->p_refcnt > 1 &&
391             (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
392                 p->p_limit->p_refcnt--;
393                 p->p_limit = limcopy(p->p_limit);
394                 alimp = &p->p_rlimit[which];
395         }
396
397         switch (which) {
398
399         case RLIMIT_CPU:
400                 if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000)
401                         p->p_limit->p_cpulimit = RLIM_INFINITY;
402                 else
403                         p->p_limit->p_cpulimit = 
404                             (rlim_t)1000000 * limp->rlim_cur;
405                 break;
406         case RLIMIT_DATA:
407                 if (limp->rlim_cur > MAXDSIZ)
408                         limp->rlim_cur = MAXDSIZ;
409                 if (limp->rlim_max > MAXDSIZ)
410                         limp->rlim_max = MAXDSIZ;
411                 break;
412
413         case RLIMIT_STACK:
414                 if (limp->rlim_cur > MAXSSIZ)
415                         limp->rlim_cur = MAXSSIZ;
416                 if (limp->rlim_max > MAXSSIZ)
417                         limp->rlim_max = MAXSSIZ;
418                 /*
419                  * Stack is allocated to the max at exec time with only
420                  * "rlim_cur" bytes accessible.  If stack limit is going
421                  * up make more accessible, if going down make inaccessible.
422                  */
423                 if (limp->rlim_cur != alimp->rlim_cur) {
424                         vm_offset_t addr;
425                         vm_size_t size;
426                         vm_prot_t prot;
427
428                         if (limp->rlim_cur > alimp->rlim_cur) {
429                                 prot = VM_PROT_ALL;
430                                 size = limp->rlim_cur - alimp->rlim_cur;
431                                 addr = USRSTACK - limp->rlim_cur;
432                         } else {
433                                 prot = VM_PROT_NONE;
434                                 size = alimp->rlim_cur - limp->rlim_cur;
435                                 addr = USRSTACK - alimp->rlim_cur;
436                         }
437                         addr = trunc_page(addr);
438                         size = round_page(size);
439                         (void) vm_map_protect(&p->p_vmspace->vm_map,
440                                               addr, addr+size, prot, FALSE);
441                 }
442                 break;
443
444         case RLIMIT_NOFILE:
445                 if (limp->rlim_cur > maxfilesperproc)
446                         limp->rlim_cur = maxfilesperproc;
447                 if (limp->rlim_max > maxfilesperproc)
448                         limp->rlim_max = maxfilesperproc;
449                 break;
450
451         case RLIMIT_NPROC:
452                 if (limp->rlim_cur > maxprocperuid)
453                         limp->rlim_cur = maxprocperuid;
454                 if (limp->rlim_max > maxprocperuid)
455                         limp->rlim_max = maxprocperuid;
456                 break;
457         }
458         *alimp = *limp;
459         return (0);
460 }
461
462 #ifndef _SYS_SYSPROTO_H_
463 struct __getrlimit_args {
464         u_int   which;
465         struct  rlimit *rlp;
466 };
467 #endif
468 /* ARGSUSED */
469 int
470 getrlimit(p, uap)
471         struct proc *p;
472         register struct __getrlimit_args *uap;
473 {
474
475         if (uap->which >= RLIM_NLIMITS)
476                 return (EINVAL);
477         return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
478             sizeof (struct rlimit)));
479 }
480
481 /*
482  * Transform the running time and tick information in proc p into user,
483  * system, and interrupt time usage.
484  */
485 void
486 calcru(p, up, sp, ip)
487         struct proc *p;
488         struct timeval *up;
489         struct timeval *sp;
490         struct timeval *ip;
491 {
492         /* {user, system, interrupt, total} {ticks, usec}; previous tu: */
493         u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu;
494         int s;
495         struct timeval tv;
496
497         /* XXX: why spl-protect ?  worst case is an off-by-one report */
498         s = splstatclock();
499         ut = p->p_uticks;
500         st = p->p_sticks;
501         it = p->p_iticks;
502         splx(s);
503
504         tt = ut + st + it;
505         if (tt == 0) {
506                 st = 1;
507                 tt = 1;
508         }
509
510         tu = p->p_runtime;
511 #ifdef SMP
512         if (p->p_oncpu != 0xff) {
513 #else
514         if (p == curproc) {
515 #endif
516                 /*
517                  * Adjust for the current time slice.  This is actually fairly
518                  * important since the error here is on the order of a time
519                  * quantum, which is much greater than the sampling error.
520                  */
521                 microuptime(&tv);
522                 tu += (tv.tv_usec - switchtime.tv_usec) +
523                     (tv.tv_sec - switchtime.tv_sec) * (int64_t)1000000;
524         }
525         ptu = p->p_stats->p_uu + p->p_stats->p_su + p->p_stats->p_iu;
526         if (tu < ptu || (int64_t)tu < 0) {
527                 /* XXX no %qd in kernel.  Truncate. */
528                 printf("calcru: negative time of %ld usec for pid %d (%s)\n",
529                        (long)tu, p->p_pid, p->p_comm);
530                 tu = ptu;
531         }
532
533         /* Subdivide tu. */
534         uu = (tu * ut) / tt;
535         su = (tu * st) / tt;
536         iu = tu - uu - su;
537
538         /* Enforce monotonicity. */
539         if (uu < p->p_stats->p_uu || su < p->p_stats->p_su ||
540             iu < p->p_stats->p_iu) {
541                 if (uu < p->p_stats->p_uu)
542                         uu = p->p_stats->p_uu;
543                 else if (uu + p->p_stats->p_su + p->p_stats->p_iu > tu)
544                         uu = tu - p->p_stats->p_su - p->p_stats->p_iu;
545                 if (st == 0)
546                         su = p->p_stats->p_su;
547                 else {
548                         su = ((tu - uu) * st) / (st + it);
549                         if (su < p->p_stats->p_su)
550                                 su = p->p_stats->p_su;
551                         else if (uu + su + p->p_stats->p_iu > tu)
552                                 su = tu - uu - p->p_stats->p_iu;
553                 }
554                 KASSERT(uu + su + p->p_stats->p_iu <= tu,
555                     ("calcru: monotonisation botch 1"));
556                 iu = tu - uu - su;
557                 KASSERT(iu >= p->p_stats->p_iu,
558                     ("calcru: monotonisation botch 2"));
559         }
560         p->p_stats->p_uu = uu;
561         p->p_stats->p_su = su;
562         p->p_stats->p_iu = iu;
563
564         up->tv_sec = uu / 1000000;
565         up->tv_usec = uu % 1000000;
566         sp->tv_sec = su / 1000000;
567         sp->tv_usec = su % 1000000;
568         if (ip != NULL) {
569                 ip->tv_sec = iu / 1000000;
570                 ip->tv_usec = iu % 1000000;
571         }
572 }
573
574 #ifndef _SYS_SYSPROTO_H_
575 struct getrusage_args {
576         int     who;
577         struct  rusage *rusage;
578 };
579 #endif
580 /* ARGSUSED */
581 int
582 getrusage(p, uap)
583         register struct proc *p;
584         register struct getrusage_args *uap;
585 {
586         register struct rusage *rup;
587
588         switch (uap->who) {
589
590         case RUSAGE_SELF:
591                 rup = &p->p_stats->p_ru;
592                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
593                 break;
594
595         case RUSAGE_CHILDREN:
596                 rup = &p->p_stats->p_cru;
597                 break;
598
599         default:
600                 return (EINVAL);
601         }
602         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
603             sizeof (struct rusage)));
604 }
605
606 void
607 ruadd(ru, ru2)
608         register struct rusage *ru, *ru2;
609 {
610         register long *ip, *ip2;
611         register int i;
612
613         timevaladd(&ru->ru_utime, &ru2->ru_utime);
614         timevaladd(&ru->ru_stime, &ru2->ru_stime);
615         if (ru->ru_maxrss < ru2->ru_maxrss)
616                 ru->ru_maxrss = ru2->ru_maxrss;
617         ip = &ru->ru_first; ip2 = &ru2->ru_first;
618         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
619                 *ip++ += *ip2++;
620 }
621
622 /*
623  * Make a copy of the plimit structure.
624  * We share these structures copy-on-write after fork,
625  * and copy when a limit is changed.
626  */
627 struct plimit *
628 limcopy(lim)
629         struct plimit *lim;
630 {
631         register struct plimit *copy;
632
633         MALLOC(copy, struct plimit *, sizeof(struct plimit),
634             M_SUBPROC, M_WAITOK);
635         bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
636         copy->p_lflags = 0;
637         copy->p_refcnt = 1;
638         return (copy);
639 }