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