summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2004-02-04 21:52:57 +0000
committerjhb <jhb@FreeBSD.org>2004-02-04 21:52:57 +0000
commit279b2b827810d149b5b8453900cdea57874ae234 (patch)
treed9c0a05d62914174d6f00ab22300e935c3e6d983 /sys/kern
parentf7b1079809c2529c50447de59fdce77a7f5a08f5 (diff)
downloadFreeBSD-src-279b2b827810d149b5b8453900cdea57874ae234.zip
FreeBSD-src-279b2b827810d149b5b8453900cdea57874ae234.tar.gz
Locking for the per-process resource limits structure.
- struct plimit includes a mutex to protect a reference count. The plimit structure is treated similarly to struct ucred in that is is always copy on write, so having a reference to a structure is sufficient to read from it without needing a further lock. - The proc lock protects the p_limit pointer and must be held while reading limits from a process to keep the limit structure from changing out from under you while reading from it. - Various global limits that are ints are not protected by a lock since int writes are atomic on all the archs we support and thus a lock wouldn't buy us anything. - All accesses to individual resource limits from a process are abstracted behind a simple lim_rlimit(), lim_max(), and lim_cur() API that return either an rlimit, or the current or max individual limit of the specified resource from a process. - dosetrlimit() was renamed to kern_setrlimit() to match existing style of other similar syscall helper functions. - The alpha OSF/1 compat layer no longer calls getrlimit() and setrlimit() (it didn't used the stackgap when it should have) but uses lim_rlimit() and kern_setrlimit() instead. - The svr4 compat no longer uses the stackgap for resource limits calls, but uses lim_rlimit() and kern_setrlimit() instead. - The ibcs2 compat no longer uses the stackgap for resource limits. It also no longer uses the stackgap for accessing sysctl's for the ibcs2_sysconf() syscall but uses kernel_sysctl() instead. As a result, ibcs2_sysconf() no longer needs Giant. - The p_rlimit macro no longer exists. Submitted by: mtm (mostly, I only did a few cleanups and catchups) Tested on: i386 Compiled on: alpha, amd64
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/imgact_aout.c8
-rw-r--r--sys/kern/imgact_elf.c11
-rw-r--r--sys/kern/imgact_gzip.c6
-rw-r--r--sys/kern/init_main.c24
-rw-r--r--sys/kern/kern_acct.c14
-rw-r--r--sys/kern/kern_descrip.c23
-rw-r--r--sys/kern/kern_exit.c11
-rw-r--r--sys/kern/kern_fork.c9
-rw-r--r--sys/kern/kern_resource.c223
-rw-r--r--sys/kern/kern_sig.c8
-rw-r--r--sys/kern/subr_trap.c8
-rw-r--r--sys/kern/sys_generic.c5
-rw-r--r--sys/kern/uipc_sockbuf.c10
-rw-r--r--sys/kern/uipc_socket2.c10
14 files changed, 247 insertions, 123 deletions
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c
index 4cb7b63..6bad705 100644
--- a/sys/kern/imgact_aout.c
+++ b/sys/kern/imgact_aout.c
@@ -177,14 +177,16 @@ exec_aout_imgact(imgp)
/*
* text/data/bss must not exceed limits
*/
- mtx_assert(&Giant, MA_OWNED);
+ PROC_LOCK(imgp->proc);
if (/* text can't exceed maximum text size */
a_out->a_text > maxtsiz ||
/* data + bss can't exceed rlimit */
- a_out->a_data + bss_size >
- imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
+ a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
+ PROC_UNLOCK(imgp->proc);
return (ENOMEM);
+ }
+ PROC_UNLOCK(imgp->proc);
/* copy in arguments and/or environment from old process */
error = exec_extract_strings(imgp);
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index ff11078..fac25e8 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -794,11 +794,11 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
* limits after loading the segments since we do
* not actually fault in all the segments pages.
*/
- if (data_size >
- imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur ||
+ PROC_LOCK(imgp->proc);
+ if (data_size > lim_cur(imgp->proc, RLIMIT_DATA) ||
text_size > maxtsiz ||
- total_size >
- imgp->proc->p_rlimit[RLIMIT_VMEM].rlim_cur) {
+ total_size > lim_cur(imgp->proc, RLIMIT_VMEM)) {
+ PROC_UNLOCK(imgp->proc);
error = ENOMEM;
goto fail;
}
@@ -815,7 +815,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
* its maximum allowed size.
*/
addr = round_page((vm_offset_t)imgp->proc->p_vmspace->vm_daddr +
- imgp->proc->p_rlimit[RLIMIT_DATA].rlim_max);
+ lim_max(imgp->proc, RLIMIT_DATA));
+ PROC_UNLOCK(imgp->proc);
imgp->entry_addr = entry;
diff --git a/sys/kern/imgact_gzip.c b/sys/kern/imgact_gzip.c
index 76602f9..b4d985a 100644
--- a/sys/kern/imgact_gzip.c
+++ b/sys/kern/imgact_gzip.c
@@ -209,16 +209,18 @@ do_aout_hdr(struct imgact_gzip * gz)
/*
* text/data/bss must not exceed limits
*/
- mtx_assert(&Giant, MA_OWNED);
+ PROC_LOCK(gz->ip->proc);
if ( /* text can't exceed maximum text size */
gz->a_out.a_text > maxtsiz ||
/* data + bss can't exceed rlimit */
gz->a_out.a_data + gz->bss_size >
- gz->ip->proc->p_rlimit[RLIMIT_DATA].rlim_cur) {
+ lim_cur(gz->ip->proc, RLIMIT_DATA)) {
+ PROC_UNLOCK(gz->ip->proc);
gz->where = __LINE__;
return (ENOMEM);
}
+ PROC_UNLOCK(gz->ip->proc);
/* Find out how far we should go */
gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data;
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 7128835..4e91f64 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -93,7 +93,6 @@ struct thread thread0;
struct kse kse0;
struct ksegrp ksegrp0;
static struct filedesc0 filedesc0;
-static struct plimit limit0;
struct vmspace vmspace0;
struct proc *initproc;
@@ -419,19 +418,18 @@ proc0_init(void *dummy __unused)
fdp->fd_fd.fd_map = fdp->fd_dmap;
/* Create the limits structures. */
- 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;
+ p->p_limit = lim_alloc();
+ for (i = 0; i < RLIM_NLIMITS; i++)
+ p->p_limit->pl_rlimit[i].rlim_cur =
+ p->p_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY;
+ p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_cur =
+ p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles;
+ p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_cur =
+ p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc;
i = ptoa(cnt.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_refcnt = 1;
+ p->p_limit->pl_rlimit[RLIMIT_RSS].rlim_max = i;
+ p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i;
+ p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3;
p->p_cpulimit = RLIM_INFINITY;
/* Allocate a prototype map so we have something to fork. */
diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c
index 827a034..613a198 100644
--- a/sys/kern/kern_acct.c
+++ b/sys/kern/kern_acct.c
@@ -228,6 +228,7 @@ acct_process(td)
int t, ret;
struct vnode *vp;
struct ucred *uc;
+ struct plimit *newlim, *oldlim;
mtx_lock(&acct_mtx);
@@ -300,11 +301,14 @@ acct_process(td)
/*
* Eliminate any file size rlimit.
*/
- if (p->p_limit->p_refcnt > 1) {
- p->p_limit->p_refcnt--;
- p->p_limit = limcopy(p->p_limit);
- }
- p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+ newlim = lim_alloc();
+ PROC_LOCK(p);
+ oldlim = p->p_limit;
+ lim_copy(newlim, oldlim);
+ newlim->pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+ p->p_limit = newlim;
+ PROC_UNLOCK(p);
+ lim_free(oldlim);
VOP_LEASE(vp, td, uc, LEASE_WRITE);
ret = vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct),
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index b6eaee2..abaac90 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -224,10 +224,10 @@ getdtablesize(td, uap)
{
struct proc *p = td->td_proc;
- mtx_lock(&Giant);
+ PROC_LOCK(p);
td->td_retval[0] =
- min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
- mtx_unlock(&Giant);
+ min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc);
+ PROC_UNLOCK(p);
return (0);
}
@@ -353,11 +353,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
case F_DUPFD:
FILEDESC_UNLOCK(fdp);
newmin = arg;
- if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
+ PROC_LOCK(p);
+ if (newmin >= lim_cur(p, RLIMIT_NOFILE) ||
newmin >= maxfilesperproc) {
+ PROC_UNLOCK(p);
error = EINVAL;
break;
}
+ PROC_UNLOCK(p);
error = do_dup(td, DUP_VARIABLE, fd, newmin, td->td_retval);
break;
@@ -572,7 +575,9 @@ do_dup(td, type, old, new, retval)
*/
if (old < 0 || new < 0)
return (EBADF);
- maxfd = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
+ PROC_LOCK(p);
+ maxfd = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc);
+ PROC_UNLOCK(p);
if (new >= maxfd)
return (EMFILE);
@@ -1213,7 +1218,9 @@ fdalloc(struct thread *td, int minfd, int *result)
FILEDESC_LOCK_ASSERT(fdp, MA_OWNED);
- maxfd = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
+ PROC_LOCK(p);
+ maxfd = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc);
+ PROC_UNLOCK(p);
/*
* Search the bitmap for a free descriptor. If none is found, try
@@ -1261,7 +1268,9 @@ fdavail(td, n)
FILEDESC_LOCK_ASSERT(fdp, MA_OWNED);
- lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
+ PROC_LOCK(p);
+ lim = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc);
+ PROC_UNLOCK(p);
if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
return (1);
last = min(fdp->fd_nfiles, lim);
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 28b39c6..f332e6b 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -119,6 +119,7 @@ exit1(struct thread *td, int rv)
struct vnode *tracevp;
struct ucred *tracecred;
#endif
+ struct plimit *plim;
GIANT_REQUIRED;
@@ -373,11 +374,11 @@ exit1(struct thread *td, int rv)
/*
* Release our limits structure.
*/
- mtx_assert(&Giant, MA_OWNED);
- if (--p->p_limit->p_refcnt == 0) {
- FREE(p->p_limit, M_SUBPROC);
- p->p_limit = NULL;
- }
+ PROC_LOCK(p);
+ plim = p->p_limit;
+ p->p_limit = NULL;
+ PROC_UNLOCK(p);
+ lim_free(plim);
/*
* Release this thread's reference to the ucred. The actual proc
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 445c606..5937c47 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -308,7 +308,7 @@ fork1(td, flags, pages, procp)
*/
PROC_LOCK(p1);
ok = chgproccnt(td->td_ucred->cr_ruidinfo, 1,
- (uid != 0) ? p1->p_rlimit[RLIMIT_NPROC].rlim_cur : 0);
+ (uid != 0) ? lim_cur(p1, RLIMIT_NPROC) : 0);
PROC_UNLOCK(p1);
if (!ok) {
error = EAGAIN;
@@ -528,14 +528,13 @@ again:
VREF(p2->p_textvp);
p2->p_fd = fd;
p2->p_fdtol = fdtol;
- PROC_UNLOCK(p1);
- PROC_UNLOCK(p2);
/*
* p_limit is copy-on-write, bump refcnt,
*/
- p2->p_limit = p1->p_limit;
- p2->p_limit->p_refcnt++;
+ p2->p_limit = lim_hold(p1->p_limit);
+ PROC_UNLOCK(p1);
+ PROC_UNLOCK(p2);
/*
* Setup linkage for kernel based threading
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index 80bf382..3b011e3 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
static int donice(struct thread *td, struct proc *chgp, int n);
+static MALLOC_DEFINE(M_PLIMIT, "plimit", "plimit structures");
static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
static struct mtx uihashtbl_mtx;
@@ -459,9 +460,7 @@ osetrlimit(td, uap)
return (error);
lim.rlim_cur = olim.rlim_cur;
lim.rlim_max = olim.rlim_max;
- mtx_lock(&Giant);
- error = dosetrlimit(td, uap->which, &lim);
- mtx_unlock(&Giant);
+ error = kern_setrlimit(td, uap->which, &lim);
return (error);
}
@@ -482,19 +481,17 @@ ogetrlimit(td, uap)
{
struct proc *p = td->td_proc;
struct orlimit olim;
+ struct rlimit rl;
int error;
if (uap->which >= RLIM_NLIMITS)
return (EINVAL);
- mtx_lock(&Giant);
- olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
- if (olim.rlim_cur == -1)
- olim.rlim_cur = 0x7fffffff;
- olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
- if (olim.rlim_max == -1)
- olim.rlim_max = 0x7fffffff;
+ PROC_LOCK(p);
+ lim_rlimit(p, uap->which, &rl);
+ PROC_UNLOCK(p);
+ olim.rlim_cur = rl.rlim_cur == -1 ? 0x7fffffff : rl.rlim_cur;
+ olim.rlim_max = rl.rlim_max == -1 ? 0x7fffffff : rl.rlim_max;
error = copyout(&olim, uap->rlp, sizeof(olim));
- mtx_unlock(&Giant);
return (error);
}
#endif /* COMPAT_43 || COMPAT_SUNOS */
@@ -519,27 +516,24 @@ setrlimit(td, uap)
if ((error = copyin(uap->rlp, &alim, sizeof (struct rlimit))))
return (error);
- mtx_lock(&Giant);
- error = dosetrlimit(td, uap->which, &alim);
- mtx_unlock(&Giant);
+ error = kern_setrlimit(td, uap->which, &alim);
return (error);
}
int
-dosetrlimit(td, which, limp)
+kern_setrlimit(td, which, limp)
struct thread *td;
u_int which;
struct rlimit *limp;
{
struct proc *p = td->td_proc;
+ struct plimit *newlim, *oldlim;
register struct rlimit *alimp;
+ rlim_t oldssiz;
int error;
- GIANT_REQUIRED;
-
if (which >= RLIM_NLIMITS)
return (EINVAL);
- alimp = &p->p_rlimit[which];
/*
* Preserve historical bugs by treating negative limits as unsigned.
@@ -549,17 +543,22 @@ dosetrlimit(td, which, limp)
if (limp->rlim_max < 0)
limp->rlim_max = RLIM_INFINITY;
+ oldssiz = 0;
+ newlim = lim_alloc();
+ PROC_LOCK(p);
+ oldlim = p->p_limit;
+ alimp = &oldlim->pl_rlimit[which];
if (limp->rlim_cur > alimp->rlim_max ||
limp->rlim_max > alimp->rlim_max)
- if ((error = suser_cred(td->td_ucred, PRISON_ROOT)))
+ if ((error = suser_cred(td->td_ucred, PRISON_ROOT))) {
+ PROC_UNLOCK(p);
+ lim_free(newlim);
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_refcnt--;
- p->p_limit = limcopy(p->p_limit);
- alimp = &p->p_rlimit[which];
- }
+ lim_copy(newlim, oldlim);
+ alimp = &newlim->pl_rlimit[which];
switch (which) {
@@ -580,53 +579,62 @@ dosetrlimit(td, which, limp)
limp->rlim_cur = maxssiz;
if (limp->rlim_max > maxssiz)
limp->rlim_max = maxssiz;
+ oldssiz = alimp->rlim_cur;
+ 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;
+ }
+ *alimp = *limp;
+ p->p_limit = newlim;
+ PROC_UNLOCK(p);
+ lim_free(oldlim);
+
+ if (which == RLIMIT_STACK) {
/*
* 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) {
+ if (limp->rlim_cur != oldssiz) {
vm_offset_t addr;
vm_size_t size;
vm_prot_t prot;
- if (limp->rlim_cur > alimp->rlim_cur) {
+ mtx_lock(&Giant);
+ if (limp->rlim_cur > oldssiz) {
prot = p->p_sysent->sv_stackprot;
- size = limp->rlim_cur - alimp->rlim_cur;
+ size = limp->rlim_cur - oldssiz;
addr = p->p_sysent->sv_usrstack -
limp->rlim_cur;
} else {
prot = VM_PROT_NONE;
- size = alimp->rlim_cur - limp->rlim_cur;
+ size = oldssiz - limp->rlim_cur;
addr = p->p_sysent->sv_usrstack -
- alimp->rlim_cur;
+ oldssiz;
}
addr = trunc_page(addr);
size = round_page(size);
(void) vm_map_protect(&p->p_vmspace->vm_map,
addr, addr+size, prot, FALSE);
+ mtx_unlock(&Giant);
}
- 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;
}
- *alimp = *limp;
return (0);
}
@@ -647,13 +655,14 @@ getrlimit(td, uap)
{
int error;
struct proc *p = td->td_proc;
+ struct rlimit rlim;
if (uap->which >= RLIM_NLIMITS)
return (EINVAL);
- mtx_lock(&Giant);
- error = copyout(&p->p_rlimit[uap->which], uap->rlp,
- sizeof (struct rlimit));
- mtx_unlock(&Giant);
+ PROC_LOCK(p);
+ lim_rlimit(p, uap->which, &rlim);
+ PROC_UNLOCK(p);
+ error = copyout(&rlim, uap->rlp, sizeof (struct rlimit));
return(error);
}
@@ -814,21 +823,107 @@ ruadd(ru, ru2)
}
/*
- * Make a copy of the plimit structure.
- * We share these structures copy-on-write after fork,
- * and copy when a limit is changed.
+ * Allocate a new resource limits structure, initialize it's
+ * reference count and mutex.
+ */
+struct plimit *
+lim_alloc(void)
+{
+ struct plimit *limp;
+
+ limp = (struct plimit *)malloc(sizeof(struct plimit), M_PLIMIT,
+ M_WAITOK | M_ZERO);
+ limp->pl_refcnt = 1;
+ mtx_init(&limp->pl_mtx, "plimit lock", NULL, MTX_DEF);
+ return (limp);
+}
+
+/*
+ * NOTE: The caller must own the proc lock this limit is associated with.
*/
struct plimit *
-limcopy(lim)
- struct plimit *lim;
+lim_hold(limp)
+ struct plimit *limp;
{
- register 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_refcnt = 1;
- return (copy);
+ LIM_LOCK(limp);
+ limp->pl_refcnt++;
+ LIM_UNLOCK(limp);
+ return (limp);
+}
+
+/*
+ * NOTE: The caller must own the proc lock this plimit belongs to.
+ */
+void
+lim_free(limp)
+ struct plimit *limp;
+{
+
+ LIM_LOCK(limp);
+ KASSERT(limp->pl_refcnt > 0, ("bad plimit refcnt: %d", limp->pl_refcnt));
+ if (--limp->pl_refcnt == 0) {
+ mtx_destroy(&limp->pl_mtx);
+ free((void *)limp, M_PLIMIT);
+ return;
+ }
+ LIM_UNLOCK(limp);
+}
+
+/*
+ * Make a copy of the plimit structure.
+ * We share these structures copy-on-write after fork.
+ */
+void
+lim_copy(dst, src)
+ struct plimit *dst, *src;
+{
+
+ KASSERT(dst->pl_refcnt == 1, ("lim_copy of shared limit"));
+ bcopy(src->pl_rlimit, dst->pl_rlimit, sizeof(src->pl_rlimit));
+}
+
+/*
+ * Obtain the hard limit for a particular system resource.
+ * which - index into the rlimit array
+ * Note: callers must hold proc lock.
+ */
+rlim_t
+lim_max(struct proc *p, int which)
+{
+ struct rlimit rl;
+
+ lim_rlimit(p, which, &rl);
+ return (rl.rlim_max);
+}
+
+/*
+ * Obtain the current (soft) limit for a particular system resource.
+ * which - index into the rlimit array
+ * Note: callers must hold proc lock.
+ */
+rlim_t
+lim_cur(struct proc *p, int which)
+{
+ struct rlimit rl;
+
+ lim_rlimit(p, which, &rl);
+ return (rl.rlim_max);
+}
+
+/*
+ * Obtain the entire rlimit structure for a particular system limit.
+ * which - index into the rlimit array
+ * rlp - address into which the rlimit structure will be placed
+ */
+void
+lim_rlimit(struct proc *p, int which, struct rlimit *rlp)
+{
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ KASSERT(which >= 0 && which < RLIM_NLIMITS,
+ ("request for invalid resource limit"));
+ *rlp = p->p_limit->pl_rlimit[which];
}
/*
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index bf224f2..aa1e19d 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2554,12 +2554,10 @@ coredump(struct thread *td)
* a corefile is truncated instead of not being created,
* if it is larger than the limit.
*/
- limit = p->p_rlimit[RLIMIT_CORE].rlim_cur;
- if (limit == 0) {
- PROC_UNLOCK(p);
- return EFBIG;
- }
+ limit = (off_t)lim_cur(p, RLIMIT_CORE);
PROC_UNLOCK(p);
+ if (limit == 0)
+ return (EFBIG);
restart:
name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid);
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index 2390087..a556d0e 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -143,7 +143,7 @@ ast(struct trapframe *framep)
struct proc *p;
struct kse *ke;
struct ksegrp *kg;
- struct rlimit *rlim;
+ struct rlimit rlim;
u_int prticks, sticks;
int sflag;
int flags;
@@ -223,13 +223,13 @@ ast(struct trapframe *framep)
}
if (sflag & PS_XCPU) {
PROC_LOCK(p);
- rlim = &p->p_rlimit[RLIMIT_CPU];
+ lim_rlimit(p, RLIMIT_CPU, &rlim);
mtx_lock_spin(&sched_lock);
- if (p->p_runtime.sec >= rlim->rlim_max) {
+ if (p->p_runtime.sec >= rlim.rlim_max) {
mtx_unlock_spin(&sched_lock);
killproc(p, "exceeded maximum CPU limit");
} else {
- if (p->p_cpulimit < rlim->rlim_max)
+ if (p->p_cpulimit < rlim.rlim_max)
p->p_cpulimit += 5;
mtx_unlock_spin(&sched_lock);
psignal(p, SIGXCPU);
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index e725f8f..7ba4f26 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -961,11 +961,14 @@ poll(td, uap)
* least enough for the current limits. We want to be reasonably
* safe, but not overly restrictive.
*/
- if ((nfds > td->td_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur) &&
+ PROC_LOCK(td->td_proc);
+ if ((nfds > lim_cur(td->td_proc, RLIMIT_NOFILE)) &&
(nfds > FD_SETSIZE)) {
+ PROC_UNLOCK(td->td_proc);
error = EINVAL;
goto done2;
}
+ PROC_UNLOCK(td->td_proc);
ni = nfds * sizeof(struct pollfd);
if (ni > sizeof(smallbits))
bits = malloc(ni, M_TEMP, M_WAITOK);
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index 64199fc..9f5da29 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -411,6 +411,7 @@ sbreserve(sb, cc, so, td)
struct socket *so;
struct thread *td;
{
+ rlim_t sbsize_limit;
/*
* td will only be NULL when we're in an interrupt
@@ -418,10 +419,15 @@ sbreserve(sb, cc, so, td)
*/
if (cc > sb_max_adj)
return (0);
+ if (td != NULL) {
+ PROC_LOCK(td->td_proc);
+ sbsize_limit = lim_cur(td->td_proc, RLIMIT_SBSIZE);
+ PROC_UNLOCK(td->td_proc);
+ } else
+ sbsize_limit = RLIM_INFINITY;
if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc,
- td ? td->td_proc->p_rlimit[RLIMIT_SBSIZE].rlim_cur : RLIM_INFINITY)) {
+ sbsize_limit))
return (0);
- }
sb->sb_mbmax = min(cc * sb_efficiency, sb_max);
if (sb->sb_lowat > sb->sb_hiwat)
sb->sb_lowat = sb->sb_hiwat;
diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c
index 64199fc..9f5da29 100644
--- a/sys/kern/uipc_socket2.c
+++ b/sys/kern/uipc_socket2.c
@@ -411,6 +411,7 @@ sbreserve(sb, cc, so, td)
struct socket *so;
struct thread *td;
{
+ rlim_t sbsize_limit;
/*
* td will only be NULL when we're in an interrupt
@@ -418,10 +419,15 @@ sbreserve(sb, cc, so, td)
*/
if (cc > sb_max_adj)
return (0);
+ if (td != NULL) {
+ PROC_LOCK(td->td_proc);
+ sbsize_limit = lim_cur(td->td_proc, RLIMIT_SBSIZE);
+ PROC_UNLOCK(td->td_proc);
+ } else
+ sbsize_limit = RLIM_INFINITY;
if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc,
- td ? td->td_proc->p_rlimit[RLIMIT_SBSIZE].rlim_cur : RLIM_INFINITY)) {
+ sbsize_limit))
return (0);
- }
sb->sb_mbmax = min(cc * sb_efficiency, sb_max);
if (sb->sb_lowat > sb->sb_hiwat)
sb->sb_lowat = sb->sb_hiwat;
OpenPOWER on IntegriCloud