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