From c0b8a06dccf87f8888e7f60ab75cc38df3d74432 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 23 May 2006 20:35:12 +0000 Subject: [PATCH] Move all the resource limit handling code into a new file, kern/kern_plimit.c. Add spinlocks for access, and mark getrlimit and setrlimit as being MPSAFE. Document how LWPs will have to be handled - basically we will have to unshare the resource structure once we start allowing multiple LWPs per process, but we can otherwise leave it in the proc structure. --- sys/conf/files | 3 +- sys/kern/init_main.c | 19 +- sys/kern/kern_acct.c | 12 +- sys/kern/kern_exit.c | 7 +- sys/kern/kern_fork.c | 16 +- sys/kern/kern_plimit.c | 424 +++++++++++++++++++++++++++++++++++++++ sys/kern/kern_resource.c | 146 +------------- sys/kern/kern_synch.c | 27 ++- sys/kern/syscalls.master | 6 +- sys/sys/kern_syscall.h | 3 +- sys/sys/proc.h | 4 +- sys/sys/resourcevar.h | 21 +- 12 files changed, 476 insertions(+), 212 deletions(-) create mode 100644 sys/kern/kern_plimit.c diff --git a/sys/conf/files b/sys/conf/files index 4bb03b7b5a..a13d2e33ef 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5 +1,5 @@ # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/sys/conf/files,v 1.124 2006/05/22 06:26:29 swildner Exp $ +# $DragonFly: src/sys/conf/files,v 1.125 2006/05/23 20:35:07 dillon Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -517,6 +517,7 @@ kern/kern_proc.c standard kern/kern_prot.c standard kern/kern_random.c standard kern/kern_resource.c standard +kern/kern_plimit.c standard kern/kern_slaballoc.c standard kern/kern_systimer.c standard kern/kern_cputimer.c standard diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index c7380472b7..164894b268 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -40,7 +40,7 @@ * * @(#)init_main.c 8.9 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/init_main.c,v 1.134.2.8 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/kern/init_main.c,v 1.53 2006/05/19 07:33:45 dillon Exp $ + * $DragonFly: src/sys/kern/init_main.c,v 1.54 2006/05/23 20:35:10 dillon Exp $ */ #include "opt_init_path.h" @@ -274,7 +274,6 @@ proc0_init(void *dummy __unused) { struct proc *p; struct lwp *lp; - unsigned i; p = &proc0; lp = &proc0.p_lwp; /* XXX lwp to be: lwp0 */ @@ -332,26 +331,14 @@ proc0_init(void *dummy __unused) p->p_procsig->ps_refcnt = 1; /* Initialize signal state for process 0. */ - siginit(&proc0); + siginit(p); /* Create the file descriptor table. */ fdinit_bootstrap(p, &filedesc0, cmask); /* Create the limits structures. */ + plimit_init0(&limit0); p->p_limit = &limit0; - for (i = 0; i < sizeof(p->p_rlimit)/sizeof(p->p_rlimit[0]); i++) - limit0.pl_rlimit[i].rlim_cur = - limit0.pl_rlimit[i].rlim_max = RLIM_INFINITY; - limit0.pl_rlimit[RLIMIT_NOFILE].rlim_cur = - limit0.pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles; - limit0.pl_rlimit[RLIMIT_NPROC].rlim_cur = - limit0.pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc; - i = ptoa(vmstats.v_free_count); - limit0.pl_rlimit[RLIMIT_RSS].rlim_max = i; - limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i; - limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3; - limit0.p_cpulimit = RLIM_INFINITY; - limit0.p_refcnt = 1; /* Allocate a prototype map so we have something to fork. */ pmap_pinit0(vmspace_pmap(&vmspace0)); diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index 0aa67e859b..f914d2e297 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -38,7 +38,7 @@ * * @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 * $FreeBSD: src/sys/kern/kern_acct.c,v 1.23.2.1 2002/07/24 18:33:55 johan Exp $ - * $DragonFly: src/sys/kern/kern_acct.c,v 1.23 2006/05/06 18:48:52 dillon Exp $ + * $DragonFly: src/sys/kern/kern_acct.c,v 1.24 2006/05/23 20:35:10 dillon Exp $ */ #include @@ -195,6 +195,7 @@ acct_process(struct proc *p) struct acct acct; struct rusage *r; struct timeval ut, st, tmp; + struct rlimit rlim; int t; struct vnode *vp; @@ -250,12 +251,9 @@ acct_process(struct proc *p) /* * Eliminate any file size rlimit. */ - if (p->p_limit->p_refcnt > 1 && - (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { - p->p_limit->p_refcnt--; - p->p_limit = limcopy(p->p_limit); - } - p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + rlim.rlim_cur = RLIM_INFINITY; + rlim.rlim_max = RLIM_INFINITY; + plimit_modify(&p->p_limit, RLIMIT_FSIZE, &rlim); /* * Write the accounting information to the file. diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index a290afca75..4f734f5d4c 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -37,7 +37,7 @@ * * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 * $FreeBSD: src/sys/kern/kern_exit.c,v 1.92.2.11 2003/01/13 22:51:16 dillon Exp $ - * $DragonFly: src/sys/kern/kern_exit.c,v 1.54 2006/05/22 06:26:30 swildner Exp $ + * $DragonFly: src/sys/kern/kern_exit.c,v 1.55 2006/05/23 20:35:10 dillon Exp $ */ #include "opt_compat.h" @@ -392,10 +392,7 @@ exit1(int rv) * * Other substructures are freed from wait(). */ - if (--p->p_limit->p_refcnt == 0) { - FREE(p->p_limit, M_SUBPROC); - p->p_limit = NULL; - } + plimit_free(&p->p_limit); /* * Release the current user process designation on the process so diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 07ee408e41..1d4f55f945 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -37,7 +37,7 @@ * * @(#)kern_fork.c 8.6 (Berkeley) 4/8/94 * $FreeBSD: src/sys/kern/kern_fork.c,v 1.72.2.14 2003/06/26 04:15:10 silby Exp $ - * $DragonFly: src/sys/kern/kern_fork.c,v 1.47 2006/05/17 20:20:49 dillon Exp $ + * $DragonFly: src/sys/kern/kern_fork.c,v 1.48 2006/05/23 20:35:10 dillon Exp $ */ #include "opt_ktrace.h" @@ -469,19 +469,7 @@ again: } } p2->p_fdtol = fdtol; - - /* - * If p_limit is still copy-on-write, bump refcnt, - * otherwise get a copy that won't be modified. - * (If PL_SHAREMOD is clear, the structure is shared - * copy-on-write.) - */ - if (p1->p_limit->p_lflags & PL_SHAREMOD) { - p2->p_limit = limcopy(p1->p_limit); - } else { - p2->p_limit = p1->p_limit; - p2->p_limit->p_refcnt++; - } + p2->p_limit = plimit_fork(p1->p_limit); /* * Preserve some more flags in subprocess. P_PROFIL has already diff --git a/sys/kern/kern_plimit.c b/sys/kern/kern_plimit.c new file mode 100644 index 0000000000..9a8b9d39fd --- /dev/null +++ b/sys/kern/kern_plimit.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2006 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (c) 1982, 1986, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94 + * $FreeBSD: src/sys/kern/kern_resource.c,v 1.55.2.5 2001/11/03 01:41:08 ps Exp $ + * $DragonFly: src/sys/kern/kern_plimit.c,v 1.1 2006/05/23 20:35:10 dillon Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +static struct plimit *plimit_copy(struct plimit *olimit); +static void plimit_exclusive(struct plimit **limitp); + +/* + * Initialize proc0's plimit structure. All later plimit structures + * are inherited through fork. + */ +void +plimit_init0(struct plimit *limit) +{ + int i; + rlim_t lim; + + for (i = 0; i < RLIM_NLIMITS; ++i) { + limit->pl_rlimit[i].rlim_cur = RLIM_INFINITY; + limit->pl_rlimit[i].rlim_max = RLIM_INFINITY; + } + limit->pl_rlimit[RLIMIT_NOFILE].rlim_cur = maxfiles; + limit->pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles; + limit->pl_rlimit[RLIMIT_NPROC].rlim_cur = maxproc; + limit->pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc; + lim = ptoa((rlim_t)vmstats.v_free_count); + limit->pl_rlimit[RLIMIT_RSS].rlim_max = lim; + limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = lim; + limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = lim / 3; + limit->p_cpulimit = RLIM_INFINITY; + limit->p_refcnt = 1; + spin_init(&limit->p_spin); +} + +/* + * Return a plimit for use by a new forked process given the one + * contained in the parent process. p_exclusive will be set if + * the parent process has more then one thread, requiring a copy. + * Otherwise we can just inherit a reference. + * + * MPSAFE + */ +struct plimit * +plimit_fork(struct plimit *limit) +{ + if (limit->p_exclusive) { + limit = plimit_copy(limit); + } else { + spin_lock_wr(&limit->p_spin); + ++limit->p_refcnt; + spin_unlock_wr(&limit->p_spin); + } + return(limit); +} + +/* + * This routine is called when the second LWP is created for a process. + * The process's limit structure must be made exclusive and a copy is + * made if necessary. + * + * If the refcnt is 1 only the LWPs associated with the caller's process + * have access to the structure, and since all we do is set the exclusive + * but we don't need a spinlock. + * + * MPSAFE + */ +static +void +plimit_exclusive(struct plimit **limitp) +{ + struct plimit *olimit = *limitp; + struct plimit *nlimit; + + if (olimit->p_refcnt == 1) { + olimit->p_exclusive = 1; + } else { + nlimit = plimit_copy(olimit); + nlimit->p_exclusive = 1; + *limitp = nlimit; + spin_lock_wr(&olimit->p_spin); + if (--olimit->p_refcnt == 0) { + spin_unlock_wr(&olimit->p_spin); + free(olimit, M_SUBPROC); + } else { + spin_unlock_wr(&olimit->p_spin); + } + } +} + +/* + * Return a copy of the passed plimit. The returned copy will have a refcnt + * of 1 and p_exclusive will be cleared. + * + * MPSAFE + */ +static +struct plimit * +plimit_copy(struct plimit *olimit) +{ + struct plimit *nlimit; + + nlimit = malloc(sizeof(struct plimit), M_SUBPROC, M_WAITOK); + + spin_lock_rd(&olimit->p_spin); + *nlimit = *olimit; + spin_unlock_rd(&olimit->p_spin); + + spin_init(&nlimit->p_spin); + nlimit->p_refcnt = 1; + nlimit->p_exclusive = 0; + return (nlimit); +} + +/* + * This routine is called to fixup a proces's p_limit structure prior + * to it being modified. If index >= 0 the specified modified is also + * made. + * + * A limit structure is potentially shared only if the process has exactly + * one LWP, otherwise it is guarenteed to be exclusive and no copy needs + * to be made. This means that we can safely replace *limitp in the copy + * case. + * + * We call plimit_exclusive() to do all the hard work, but the result does + * not actually have to be exclusive since the original was not, so just + * clear p_exclusive afterwords. + * + * MPSAFE + */ +void +plimit_modify(struct plimit **limitp, int index, struct rlimit *rlim) +{ + struct plimit *limit = *limitp; + + if (limit->p_exclusive == 0 && limit->p_refcnt > 1) { + plimit_exclusive(limitp); + limit = *limitp; + limit->p_exclusive = 0; + } + if (index >= 0) { + spin_lock_wr(&limit->p_spin); + limit->pl_rlimit[index] = *rlim; + spin_unlock_wr(&limit->p_spin); + } +} + +/* + * Destroy a process's plimit structure. + * + * MPSAFE + */ +void +plimit_free(struct plimit **limitp) +{ + struct plimit *limit; + + if ((limit = *limitp) != NULL) { + *limitp = NULL; + + spin_lock_wr(&limit->p_spin); + if (--limit->p_refcnt == 0) { + spin_unlock_wr(&limit->p_spin); + free(limit, M_SUBPROC); + } else { + spin_unlock_wr(&limit->p_spin); + } + } +} + +/* + * Modify a resource limit (from system call) + * + * MPSAFE + */ +int +kern_setrlimit(u_int which, struct rlimit *limp) +{ + struct proc *p = curproc; + struct plimit *limit; + struct rlimit *alimp; + int error; + + if (which >= RLIM_NLIMITS) + return (EINVAL); + + /* + * We will be modifying a resource, make a copy if necessary. + */ + plimit_modify(&p->p_limit, -1, NULL); + limit = p->p_limit; + alimp = &limit->pl_rlimit[which]; + + /* + * Preserve historical bugs by treating negative limits as unsigned. + */ + if (limp->rlim_cur < 0) + limp->rlim_cur = RLIM_INFINITY; + if (limp->rlim_max < 0) + limp->rlim_max = RLIM_INFINITY; + + spin_lock_rd(&limit->p_spin); + if (limp->rlim_cur > alimp->rlim_max || + limp->rlim_max > alimp->rlim_max) { + spin_unlock_rd(&limit->p_spin); + if ((error = suser_cred(p->p_ucred, PRISON_ROOT))) + return (error); + } else { + spin_unlock_rd(&limit->p_spin); + } + if (limp->rlim_cur > limp->rlim_max) + limp->rlim_cur = limp->rlim_max; + + switch (which) { + case RLIMIT_CPU: + spin_lock_wr(&limit->p_spin); + if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000) + limit->p_cpulimit = RLIM_INFINITY; + else + limit->p_cpulimit = (rlim_t)1000000 * limp->rlim_cur; + spin_unlock_wr(&limit->p_spin); + break; + case RLIMIT_DATA: + if (limp->rlim_cur > maxdsiz) + limp->rlim_cur = maxdsiz; + if (limp->rlim_max > maxdsiz) + limp->rlim_max = maxdsiz; + break; + + case RLIMIT_STACK: + if (limp->rlim_cur > maxssiz) + limp->rlim_cur = maxssiz; + if (limp->rlim_max > maxssiz) + limp->rlim_max = maxssiz; + /* + * Stack is allocated to the max at exec time with only + * "rlim_cur" bytes accessible. If stack limit is going + * up make more accessible, if going down make inaccessible. + */ + spin_lock_rd(&limit->p_spin); + if (limp->rlim_cur != alimp->rlim_cur) { + vm_offset_t addr; + vm_size_t size; + vm_prot_t prot; + + if (limp->rlim_cur > alimp->rlim_cur) { + prot = VM_PROT_ALL; + size = limp->rlim_cur - alimp->rlim_cur; + addr = USRSTACK - limp->rlim_cur; + } else { + prot = VM_PROT_NONE; + size = alimp->rlim_cur - limp->rlim_cur; + addr = USRSTACK - alimp->rlim_cur; + } + spin_unlock_rd(&limit->p_spin); + addr = trunc_page(addr); + size = round_page(size); + (void) vm_map_protect(&p->p_vmspace->vm_map, + addr, addr+size, prot, FALSE); + } else { + spin_unlock_rd(&limit->p_spin); + } + break; + + case RLIMIT_NOFILE: + if (limp->rlim_cur > maxfilesperproc) + limp->rlim_cur = maxfilesperproc; + if (limp->rlim_max > maxfilesperproc) + limp->rlim_max = maxfilesperproc; + break; + + case RLIMIT_NPROC: + if (limp->rlim_cur > maxprocperuid) + limp->rlim_cur = maxprocperuid; + if (limp->rlim_max > maxprocperuid) + limp->rlim_max = maxprocperuid; + if (limp->rlim_cur < 1) + limp->rlim_cur = 1; + if (limp->rlim_max < 1) + limp->rlim_max = 1; + break; + case RLIMIT_POSIXLOCKS: + if (limp->rlim_cur > maxposixlocksperuid) + limp->rlim_cur = maxposixlocksperuid; + if (limp->rlim_max > maxposixlocksperuid) + limp->rlim_max = maxposixlocksperuid; + break; + } + spin_lock_wr(&limit->p_spin); + *alimp = *limp; + spin_unlock_wr(&limit->p_spin); + return (0); +} + +/* + * The rlimit indexed by which is returned in the second argument. + * + * MPSAFE + */ +int +kern_getrlimit(u_int which, struct rlimit *limp) +{ + struct proc *p = curproc; + struct plimit *limit; + + if (which >= RLIM_NLIMITS) + return (EINVAL); + + limit = p->p_limit; + spin_lock_rd(&limit->p_spin); + *limp = p->p_rlimit[which]; + spin_unlock_rd(&limit->p_spin); + return (0); +} + +/* + * Determine if the cpu limit has been reached and return an operations + * code for the caller to perform. + * + * MPSAFE + */ +int +plimit_testcpulimit(struct plimit *limit, u_int64_t ttime) +{ + struct rlimit *rlim; + int mode; + + mode = PLIMIT_TESTCPU_OK; + if (limit->p_cpulimit != RLIM_INFINITY) { + spin_lock_rd(&limit->p_spin); + if (ttime > limit->p_cpulimit) { + rlim = &limit->pl_rlimit[RLIMIT_CPU]; + if (ttime / (rlim_t)1000000 >= rlim->rlim_max + 5) { + mode = PLIMIT_TESTCPU_KILL; + } else { + mode = PLIMIT_TESTCPU_XCPU; + } + } + spin_unlock_rd(&limit->p_spin); + } + return(mode); +} + diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 16c94214e3..17078d0926 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -37,7 +37,7 @@ * * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/kern_resource.c,v 1.55.2.5 2001/11/03 01:41:08 ps Exp $ - * $DragonFly: src/sys/kern/kern_resource.c,v 1.25 2006/03/23 15:21:41 drhodus Exp $ + * $DragonFly: src/sys/kern/kern_resource.c,v 1.26 2006/05/23 20:35:10 dillon Exp $ */ #include "opt_compat.h" @@ -292,132 +292,6 @@ setrlimit(struct __setrlimit_args *uap) return (error); } -int -kern_setrlimit(u_int which, struct rlimit *limp) -{ - struct proc *p = curproc; - struct rlimit *alimp; - int error; - - if (which >= RLIM_NLIMITS) - return (EINVAL); - alimp = &p->p_rlimit[which]; - - /* - * Preserve historical bugs by treating negative limits as unsigned. - */ - if (limp->rlim_cur < 0) - limp->rlim_cur = RLIM_INFINITY; - if (limp->rlim_max < 0) - limp->rlim_max = RLIM_INFINITY; - - if (limp->rlim_cur > alimp->rlim_max || - limp->rlim_max > alimp->rlim_max) - if ((error = suser_cred(p->p_ucred, PRISON_ROOT))) - return (error); - if (limp->rlim_cur > limp->rlim_max) - limp->rlim_cur = limp->rlim_max; - if (p->p_limit->p_refcnt > 1 && - (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { - p->p_limit->p_refcnt--; - p->p_limit = limcopy(p->p_limit); - alimp = &p->p_rlimit[which]; - } - - switch (which) { - - case RLIMIT_CPU: - if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000) - p->p_limit->p_cpulimit = RLIM_INFINITY; - else - p->p_limit->p_cpulimit = - (rlim_t)1000000 * limp->rlim_cur; - break; - case RLIMIT_DATA: - if (limp->rlim_cur > maxdsiz) - limp->rlim_cur = maxdsiz; - if (limp->rlim_max > maxdsiz) - limp->rlim_max = maxdsiz; - break; - - case RLIMIT_STACK: - if (limp->rlim_cur > maxssiz) - limp->rlim_cur = maxssiz; - if (limp->rlim_max > maxssiz) - limp->rlim_max = maxssiz; - /* - * Stack is allocated to the max at exec time with only - * "rlim_cur" bytes accessible. If stack limit is going - * up make more accessible, if going down make inaccessible. - */ - if (limp->rlim_cur != alimp->rlim_cur) { - vm_offset_t addr; - vm_size_t size; - vm_prot_t prot; - - if (limp->rlim_cur > alimp->rlim_cur) { - prot = VM_PROT_ALL; - size = limp->rlim_cur - alimp->rlim_cur; - addr = USRSTACK - limp->rlim_cur; - } else { - prot = VM_PROT_NONE; - size = alimp->rlim_cur - limp->rlim_cur; - addr = USRSTACK - alimp->rlim_cur; - } - addr = trunc_page(addr); - size = round_page(size); - (void) vm_map_protect(&p->p_vmspace->vm_map, - addr, addr+size, prot, FALSE); - } - break; - - case RLIMIT_NOFILE: - if (limp->rlim_cur > maxfilesperproc) - limp->rlim_cur = maxfilesperproc; - if (limp->rlim_max > maxfilesperproc) - limp->rlim_max = maxfilesperproc; - break; - - case RLIMIT_NPROC: - if (limp->rlim_cur > maxprocperuid) - limp->rlim_cur = maxprocperuid; - if (limp->rlim_max > maxprocperuid) - limp->rlim_max = maxprocperuid; - if (limp->rlim_cur < 1) - limp->rlim_cur = 1; - if (limp->rlim_max < 1) - limp->rlim_max = 1; - break; - case RLIMIT_POSIXLOCKS: - if (limp->rlim_cur > maxposixlocksperuid) - limp->rlim_cur = maxposixlocksperuid; - if (limp->rlim_max > maxposixlocksperuid) - limp->rlim_max = maxposixlocksperuid; - break; - } - *alimp = *limp; - return (0); -} - -/* - * The rlimit indexed by which is returned in the second argument. - * - * MP SAFE - */ -int -kern_getrlimit(u_int which, struct rlimit *limp) -{ - struct thread *td = curthread; - struct proc *p = td->td_proc; - - if (which >= RLIM_NLIMITS) - return (EINVAL); - - *limp = p->p_rlimit[which]; - - return (0); -} - int getrlimit(struct __getrlimit_args *uap) { @@ -502,24 +376,6 @@ ruadd(struct rusage *ru, struct rusage *ru2) *ip++ += *ip2++; } -/* - * Make a copy of the plimit structure. - * We share these structures copy-on-write after fork, - * and copy when a limit is changed. - */ -struct plimit * -limcopy(struct plimit *lim) -{ - struct plimit *copy; - - MALLOC(copy, struct plimit *, sizeof(struct plimit), - M_SUBPROC, M_WAITOK); - bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit)); - copy->p_lflags = 0; - copy->p_refcnt = 1; - return (copy); -} - /* * Find the uidinfo structure for a uid. This structure is used to * track the total resource consumption (process count, socket buffer diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 3d25489be0..a0671e9076 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -37,7 +37,7 @@ * * @(#)kern_synch.c 8.9 (Berkeley) 5/19/95 * $FreeBSD: src/sys/kern/kern_synch.c,v 1.87.2.6 2002/10/13 07:29:53 kbyanc Exp $ - * $DragonFly: src/sys/kern/kern_synch.c,v 1.59 2006/04/14 20:08:34 dillon Exp $ + * $DragonFly: src/sys/kern/kern_synch.c,v 1.60 2006/05/23 20:35:10 dillon Exp $ */ #include "opt_ktrace.h" @@ -171,7 +171,6 @@ SYSCTL_INT(_kern, OID_AUTO, fscale, CTLFLAG_RD, 0, FSCALE, ""); static void schedcpu(void *arg) { - struct rlimit *rlim; struct proc *p; u_int64_t ttime; @@ -212,25 +211,23 @@ schedcpu(void *arg) continue; } ttime = p->p_thread->td_sticks + p->p_thread->td_uticks; - if (p->p_limit->p_cpulimit != RLIM_INFINITY && - ttime > p->p_limit->p_cpulimit - ) { - rlim = &p->p_rlimit[RLIMIT_CPU]; - if (ttime / (rlim_t)1000000 >= rlim->rlim_max) { - killproc(p, "exceeded maximum CPU limit"); - } else { + switch(plimit_testcpulimit(p->p_limit, ttime)) { + case PLIMIT_TESTCPU_KILL: + killproc(p, "exceeded maximum CPU limit"); + break; + case PLIMIT_TESTCPU_XCPU: + if ((p->p_flag & P_XCPU) == 0) { + p->p_flag |= P_XCPU; psignal(p, SIGXCPU); - if (rlim->rlim_cur < rlim->rlim_max) { - /* XXX: we should make a private copy */ - rlim->rlim_cur += 5; - } } - crit_exit(); break; + default: + crit_exit(); + continue; } crit_exit(); + break; } - wakeup((caddr_t)&lbolt); wakeup((caddr_t)&lbolt_syncer); callout_reset(&schedcpu_callout, hz, schedcpu, NULL); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 0108af9a50..2c4eacf31b 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ - $DragonFly: src/sys/kern/syscalls.master,v 1.32 2006/04/26 17:17:56 dillon Exp $ + $DragonFly: src/sys/kern/syscalls.master,v 1.33 2006/05/23 20:35:10 dillon Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 ; $FreeBSD: src/sys/kern/syscalls.master,v 1.72.2.10 2002/07/12 08:22:46 alfred Exp $ @@ -229,8 +229,8 @@ 141 COMPAT BSD { int getpeername(int fdes, caddr_t asa, int *alen); } 142 COMPAT BSD { long gethostid(void); } 143 COMPAT BSD { int sethostid(long hostid); } -144 COMPAT BSD { int getrlimit(u_int which, struct orlimit *rlp); } -145 COMPAT BSD { int setrlimit(u_int which, struct orlimit *rlp); } +144 MSAFE COMPAT BSD { int getrlimit(u_int which, struct orlimit *rlp); } +145 MSAFE COMPAT BSD { int setrlimit(u_int which, struct orlimit *rlp); } 146 COMPAT BSD { int killpg(int pgid, int signum); } 147 STD POSIX { int setsid(void); } 148 STD BSD { int quotactl(char *path, int cmd, int uid, \ diff --git a/sys/sys/kern_syscall.h b/sys/sys/kern_syscall.h index cc66d3a9a8..499bb0987e 100644 --- a/sys/sys/kern_syscall.h +++ b/sys/sys/kern_syscall.h @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/kern_syscall.h,v 1.30 2006/05/06 02:43:13 dillon Exp $ + * $DragonFly: src/sys/sys/kern_syscall.h,v 1.31 2006/05/23 20:35:12 dillon Exp $ */ #ifndef _SYS_KERN_SYSCALL_H_ @@ -40,6 +40,7 @@ enum dup_type {DUP_FIXED, DUP_VARIABLE}; union fcntl_dat; struct image_args; +struct plimit; struct mbuf; struct msghdr; struct namecache; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 33a926f4be..2e016911a3 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -37,7 +37,7 @@ * * @(#)proc.h 8.15 (Berkeley) 5/19/95 * $FreeBSD: src/sys/sys/proc.h,v 1.99.2.9 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/sys/proc.h,v 1.75 2006/05/21 03:43:47 dillon Exp $ + * $DragonFly: src/sys/sys/proc.h,v 1.76 2006/05/23 20:35:12 dillon Exp $ */ #ifndef _SYS_PROC_H_ @@ -297,6 +297,7 @@ struct proc { int p_numposixlocks; /* number of POSIX locks */ struct lwp p_lwp; /* Embedded lwp XXX */ + struct spinlock p_spin; /* Spinlock for LWP access to proc */ }; #if defined(_KERNEL) @@ -355,6 +356,7 @@ struct proc { #define P_INEXEC 0x8000000 /* Process is in execve(). */ #define P_PASSIVE_ACQ 0x10000000 /* Passive acquire cpu (see kern_switch) */ #define P_UPCALLWAIT 0x20000000 /* Wait for upcall or signal */ +#define P_XCPU 0x40000000 /* SIGXCPU */ #ifdef _KERNEL diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index fa1e22399e..608e3d7414 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -32,7 +32,7 @@ * * @(#)resourcevar.h 8.4 (Berkeley) 1/9/95 * $FreeBSD: src/sys/sys/resourcevar.h,v 1.16.2.1 2000/09/07 19:13:55 truckman Exp $ - * $DragonFly: src/sys/sys/resourcevar.h,v 1.12 2006/05/20 02:42:13 dillon Exp $ + * $DragonFly: src/sys/sys/resourcevar.h,v 1.13 2006/05/23 20:35:12 dillon Exp $ */ #ifndef _SYS_RESOURCEVAR_H_ @@ -53,6 +53,9 @@ #ifndef _SYS_TIME_H_ #include #endif +#ifndef _SYS_SPINLOCK_H_ +#include +#endif /* * Kernel per-process accounting / statistics @@ -82,12 +85,16 @@ struct uprof { /* profile arguments */ */ struct plimit { struct rlimit pl_rlimit[RLIM_NLIMITS]; -#define PL_SHAREMOD 0x01 /* modifications are shared */ - int p_lflags; int p_refcnt; /* number of references */ + int p_exclusive; /* exclusive to proc due to lwp's */ rlim_t p_cpulimit; /* current cpu limit in usec */ + struct spinlock p_spin; }; +#define PLIMIT_TESTCPU_OK 0 +#define PLIMIT_TESTCPU_XCPU 1 +#define PLIMIT_TESTCPU_KILL 2 + /* * Per uid resource consumption */ @@ -112,7 +119,6 @@ void calcru (struct proc *p, struct timeval *up, struct timeval *sp, int chgproccnt (struct uidinfo *uip, int diff, int max); int chgsbsize (struct uidinfo *uip, u_long *hiwat, u_long to, rlim_t max); int fuswintr (void *base); -struct plimit *limcopy (struct plimit *lim); void ruadd (struct rusage *ru, struct rusage *ru2); int suswintr (void *base, int word); struct uidinfo *uifind (uid_t uid); @@ -120,6 +126,13 @@ void uihold (struct uidinfo *uip); void uidrop (struct uidinfo *uip); void uireplace (struct uidinfo **puip, struct uidinfo *nuip); void uihashinit (void); + +void plimit_init0(struct plimit *); +struct plimit *plimit_fork(struct plimit *); +int plimit_testcpulimit(struct plimit *, u_int64_t); +void plimit_modify(struct plimit **, int, struct rlimit *); +void plimit_free(struct plimit **); + #endif #endif /* !_SYS_RESOURCEVAR_H_ */ -- 2.41.0