summaryrefslogtreecommitdiffstats
path: root/sys/compat/svr4/svr4_misc.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2001-01-23 21:30:25 +0000
committerjhb <jhb@FreeBSD.org>2001-01-23 21:30:25 +0000
commit0742fd6c671f70d25a972540ce9099cc61f236c1 (patch)
treeee65597f5b4836a4d0631a4d82b593bdedf589be /sys/compat/svr4/svr4_misc.c
parent1a36de8090ca93b96cbcf1600aa926043c3cd362 (diff)
downloadFreeBSD-src-0742fd6c671f70d25a972540ce9099cc61f236c1.zip
FreeBSD-src-0742fd6c671f70d25a972540ce9099cc61f236c1.tar.gz
- Add proc locking.
- Fix several bugs in the wait syscall, including freeing the actual proc start, freeing the args, freeing the prison, and other minor nits. - Use appropriate queue(3) macros. - Use zpfind() instead of walking zombproc ourselves.
Diffstat (limited to 'sys/compat/svr4/svr4_misc.c')
-rw-r--r--sys/compat/svr4/svr4_misc.c139
1 files changed, 104 insertions, 35 deletions
diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c
index bc45271..96559a2 100644
--- a/sys/compat/svr4/svr4_misc.c
+++ b/sys/compat/svr4/svr4_misc.c
@@ -80,6 +80,9 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_map.h>
+#if defined(__FreeBSD__)
+#include <vm/vm_zone.h>
+#endif
#if defined(NetBSD)
# if defined(UVM)
@@ -245,6 +248,7 @@ svr4_sys_getdents64(p, uap)
struct uio auio;
struct iovec aiov;
struct vattr va;
+ struct ucred *uc;
off_t off;
struct svr4_dirent64 svr4_dirent;
int buflen, error, eofflag, nbytes, justone;
@@ -265,7 +269,13 @@ svr4_sys_getdents64(p, uap)
if (vp->v_type != VDIR)
return (EINVAL);
- if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
+ PROC_LOCK(p);
+ uc = p->p_ucred;
+ crhold(uc);
+ PROC_UNLOCK(p);
+ error = VOP_GETATTR(vp, &va, uc, p);
+ crfree(uc);
+ if (error != 0) {
return error;
}
@@ -587,6 +597,7 @@ svr4_sys_fchroot(p, uap)
struct filedesc *fdp = p->p_fd;
struct vnode *vp;
struct file *fp;
+ struct ucred *uc;
int error;
if ((error = suser(p)) != 0)
@@ -597,8 +608,14 @@ svr4_sys_fchroot(p, uap)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_type != VDIR)
error = ENOTDIR;
- else
+ else {
+ PROC_LOCK(p);
+ uc = p->p_ucred;
+ crhold(uc);
+ PROC_UNLOCK(p);
error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
+ crfree(uc);
+ }
VOP_UNLOCK(vp, 0, p);
if (error)
return error;
@@ -784,6 +801,8 @@ svr4_sys_break(p, uap)
base = round_page((vm_offset_t) vm->vm_daddr);
ns = (vm_offset_t)SCARG(uap, nsize);
new = round_page(ns);
+ /* For p_rlimit. */
+ mtx_assert(&Giant, MA_OWNED);
if (new > base) {
if ((new - base) > (unsigned) p->p_rlimit[RLIMIT_DATA].rlim_cur) {
return ENOMEM;
@@ -888,6 +907,8 @@ svr4_sys_ulimit(p, uap)
switch (SCARG(uap, cmd)) {
case SVR4_GFILLIM:
+ /* For p_rlimit below. */
+ mtx_assert(&Giant, MA_OWNED);
*retval = p->p_rlimit[RLIMIT_FSIZE].rlim_cur / 512;
if (*retval == -1)
*retval = 0x7fffffff;
@@ -903,6 +924,7 @@ svr4_sys_ulimit(p, uap)
stackgap_alloc(&sg, sizeof *url);
krl.rlim_cur = SCARG(uap, newlimit) * 512;
+ mtx_assert(&Giant, MA_OWNED);
krl.rlim_max = p->p_rlimit[RLIMIT_FSIZE].rlim_max;
error = copyout(&krl, url, sizeof(*url));
@@ -916,6 +938,7 @@ svr4_sys_ulimit(p, uap)
if (error)
return error;
+ mtx_assert(&Giant, MA_OWNED);
*retval = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
if (*retval == -1)
*retval = 0x7fffffff;
@@ -925,7 +948,10 @@ svr4_sys_ulimit(p, uap)
case SVR4_GMEMLIM:
{
struct vmspace *vm = p->p_vmspace;
- register_t r = p->p_rlimit[RLIMIT_DATA].rlim_cur;
+ register_t r;
+
+ mtx_assert(&Giant, MA_OWNED);
+ r = p->p_rlimit[RLIMIT_DATA].rlim_cur;
if (r == -1)
r = 0x7fffffff;
@@ -937,6 +963,7 @@ svr4_sys_ulimit(p, uap)
}
case SVR4_GDESLIM:
+ mtx_assert(&Giant, MA_OWNED);
*retval = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
if (*retval == -1)
*retval = 0x7fffffff;
@@ -953,17 +980,10 @@ svr4_pfind(pid)
{
struct proc *p;
- ALLPROC_LOCK(AP_SHARED);
/* look in the live processes */
- if ((p = pfind(pid)) != NULL)
- goto out;
-
- /* look in the zombies */
- for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
- if (p->p_pid == pid)
- break;
-out:
- ALLPROC_LOCK(AP_RELEASE);
+ if ((p = pfind(pid)) == NULL)
+ /* look in the zombies */
+ p = zpfind(pid);
return p;
}
@@ -1133,6 +1153,7 @@ svr4_setinfo(p, st, s)
if (p) {
i.si_pid = p->p_pid;
+ mtx_enter(&sched_lock, MTX_SPIN);
if (p->p_stat == SZOMB) {
i.si_stime = p->p_ru->ru_stime.tv_sec;
i.si_utime = p->p_ru->ru_utime.tv_sec;
@@ -1141,6 +1162,7 @@ svr4_setinfo(p, st, s)
i.si_stime = p->p_stats->p_ru.ru_stime.tv_sec;
i.si_utime = p->p_stats->p_ru.ru_utime.tv_sec;
}
+ mtx_exit(&sched_lock, MTX_SPIN);
}
if (WIFEXITED(st)) {
@@ -1206,7 +1228,7 @@ svr4_sys_waitsys(p, uap)
loop:
nfound = 0;
PROCTREE_LOCK(PT_SHARED);
- for (q = p->p_children.lh_first; q != 0; q = q->p_sibling.le_next) {
+ LIST_FOREACH(q, &p->p_children, p_sibling) {
if (SCARG(uap, id) != WAIT_ANY &&
q->p_pid != SCARG(uap, id) &&
q->p_pgid != -SCARG(uap, id)) {
@@ -1215,13 +1237,17 @@ loop:
continue;
}
nfound++;
+ PROC_LOCK(q);
+ mtx_enter(&sched_lock, MTX_SPIN);
if (q->p_stat == SZOMB &&
((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)))) {
+ mtx_exit(&sched_lock, MTX_SPIN);
+ PROC_UNLOCK(q);
PROCTREE_LOCK(PT_RELEASE);
*retval = 0;
DPRINTF(("found %d\n", q->p_pid));
- if ((error = svr4_setinfo(q, q->p_xstat,
- SCARG(uap, info))) != 0)
+ error = svr4_setinfo(q, q->p_xstat, SCARG(uap, info));
+ if (error != 0)
return error;
@@ -1234,60 +1260,95 @@ loop:
* If we got the child via ptrace(2) or procfs, and
* the parent is different (meaning the process was
* attached, rather than run as a child), then we need
- * to give it back to the ol dparent, and send the
+ * to give it back to the old parent, and send the
* parent a SIGCHLD. The rest of the cleanup will be
* done when the old parent waits on the child.
*/
+ PROC_LOCK(q);
if (q->p_flag & P_TRACED) {
+ PROC_UNLOCK(q);
PROCTREE_LOCK(PT_EXCLUSIVE);
if (q->p_oppid != q->p_pptr->p_pid) {
t = pfind(q->p_oppid);
proc_reparent(q, t ? t : initproc);
+ PROCTREE_LOCK(PT_RELEASE);
+ PROC_LOCK(q);
q->p_oppid = 0;
q->p_flag &= ~(P_TRACED | P_WAITED);
+ PROC_UNLOCK(q);
+ PROCTREE_LOCK(PT_SHARED);
wakeup((caddr_t)q->p_pptr);
PROCTREE_LOCK(PT_RELEASE);
return 0;
}
PROCTREE_LOCK(PT_RELEASE);
- }
+ } else
+ PROC_UNLOCK(q);
q->p_xstat = 0;
ruadd(&p->p_stats->p_cru, q->p_ru);
-
FREE(q->p_ru, M_ZOMBIE);
+ q->p_ru = 0;
/*
- * Finally finished with old proc entry.
- * Unlink it from its process group and free it.
+ * Decrement the count of procs running with this uid.
*/
- leavepgrp(q);
-
- ALLPROC_LOCK(AP_EXCLUSIVE);
- LIST_REMOVE(q, p_list); /* off zombproc */
- ALLPROC_LOCK(AP_RELEASE);
-
- PROCTREE_LOCK(PT_EXCLUSIVE);
- LIST_REMOVE(q, p_sibling);
- PROCTREE_LOCK(PT_RELEASE);
+ (void)chgproccnt(q->p_cred->p_uidinfo, -1, 0);
/*
- * Decrement the count of procs running with this uid.
+ * Release reference to text vnode.
*/
- (void)chgproccnt(q->p_cred->p_uidinfo, -1, 0);
+ if (q->p_textvp)
+ vrele(q->p_textvp);
/*
* Free up credentials.
*/
+ PROC_LOCK(q);
if (--q->p_cred->p_refcnt == 0) {
crfree(q->p_ucred);
+ uifree(q->p_cred->p_uidinfo);
FREE(q->p_cred, M_SUBPROC);
+ q->p_cred = NULL;
+ }
+
+ /*
+ * Destroy empty prisons
+ */
+ if (q->p_prison && !--q->p_prison->pr_ref) {
+ if (q->p_prison->pr_linux != NULL)
+ FREE(q->p_prison->pr_linux, M_PRISON);
+ FREE(q->p_prison, M_PRISON);
}
/*
- * Release reference to text vnode
+ * Remove unused arguments
*/
- if (q->p_textvp)
- vrele(q->p_textvp);
+ if (q->p_args && --q->p_args->ar_ref == 0)
+ FREE(q->p_args, M_PARGS);
+ PROC_UNLOCK(q);
+
+ /*
+ * Finally finished with old proc entry.
+ * Unlink it from its process group and free it.
+ */
+ leavepgrp(q);
+
+ ALLPROC_LOCK(AP_EXCLUSIVE);
+ LIST_REMOVE(q, p_list); /* off zombproc */
+ ALLPROC_LOCK(AP_RELEASE);
+
+ PROCTREE_LOCK(PT_EXCLUSIVE);
+ LIST_REMOVE(q, p_sibling);
+ PROCTREE_LOCK(PT_RELEASE);
+
+ PROC_LOCK(q);
+ if (--q->p_procsig->ps_refcnt == 0) {
+ if (q->p_sigacts != &q->p_addr->u_sigacts)
+ FREE(p->q_sigacts, M_SUBPROC);
+ FREE(q->p_procsig, M_SUBPROC);
+ q->p_procsig = NULL;
+ }
+ PROC_UNLOCK(q);
/*
* Give machine-dependent layer a chance
@@ -1298,19 +1359,27 @@ loop:
#if defined(__NetBSD__)
pool_put(&proc_pool, q);
#endif
+#ifdef __FreeBSD__
+ mtx_destroy(&q->p_mtx);
+ zfree(proc_zone, q);
+#endif
nprocs--;
return 0;
}
if (q->p_stat == SSTOP && (q->p_flag & P_WAITED) == 0 &&
(q->p_flag & P_TRACED ||
(SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED)))) {
+ mtx_exit(&sched_lock, MTX_SPIN);
DPRINTF(("jobcontrol %d\n", q->p_pid));
if (((SCARG(uap, options) & SVR4_WNOWAIT)) == 0)
q->p_flag |= P_WAITED;
+ PROC_UNLOCK(q);
*retval = 0;
return svr4_setinfo(q, W_STOPCODE(q->p_xstat),
SCARG(uap, info));
}
+ mtx_exit(&sched_lock, MTX_SPIN);
+ PROC_UNLOCK(q);
}
if (nfound == 0)
OpenPOWER on IntegriCloud