kernel - Make numerous proc accesses use p->p_token instead of proc_token.
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 14 Feb 2011 04:57:32 +0000 (20:57 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 14 Feb 2011 05:07:12 +0000 (21:07 -0800)
* pfind() zpfind() now returns a referenced proc structure, callers must
  release the proc with PRELE().  Callers no longer need to hold proc_token
  for stable access.

* Enhance pgrp, adding pgrp->pg_token and pgrp->pg_refs in addition to
  pgrp->pg_lock.  The lock is used to interlock races between fork() and
  signals while the token and refs are used to control access.

* Add pfindn(), a version of pfind() which does not ref the returned proc.
  Some code still uses it (linux emulation) ---> needs work.

* Add pgref() and pgrel() to mess with the pgrp's pg_refs.  pgrel()
  automatically destroys the pgrp when the last reference goes away.

* Most process group operations now use the per-process token instead of
  proc_token, though pgfind() still needs it temporarily.

* pgfind() now returns a referenced pgrp or NULL.

* Interlock signal handling with p->p_token instead of proc_token.

* Adjust most nice/priority functions to use the per-process token.

* Add protective PHOLD()s in various places in the signal code, the
  ptrace code, and procfs.

* Change funsetown() to take the address of the sigio pointer to match
  fsetown(), add sanity assertions.

* pgrp's in tty sessions are now ref-counted.

37 files changed:
sys/dev/drm/drm_drv.c
sys/dev/misc/syscons/scmouse.c
sys/dev/misc/syscons/syscons.c
sys/emulation/linux/i386/linprocfs/linprocfs.h
sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c
sys/emulation/linux/i386/linux_machdep.c
sys/emulation/linux/i386/linux_ptrace.c
sys/emulation/linux/linux_futex.c
sys/emulation/linux/linux_misc.c
sys/emulation/linux/linux_signal.c
sys/kern/init_main.c
sys/kern/kern_descrip.c
sys/kern/kern_event.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/kern_ktrace.c
sys/kern/kern_p1003_1b.c
sys/kern/kern_proc.c
sys/kern/kern_prot.c
sys/kern/kern_resource.c
sys/kern/kern_sig.c
sys/kern/subr_log.c
sys/kern/sys_pipe.c
sys/kern/sys_process.c
sys/kern/tty.c
sys/kern/uipc_socket.c
sys/kern/uipc_syscalls.c
sys/net/bpf.c
sys/net/tap/if_tap.c
sys/net/tun/if_tun.c
sys/platform/pc32/i386/db_trace.c
sys/sys/filedesc.h
sys/sys/proc.h
sys/vfs/procfs/procfs.h
sys/vfs/procfs/procfs_ctl.c
sys/vfs/procfs/procfs_subr.c
sys/vfs/procfs/procfs_vnops.c

index 8ddd753..50de37b 100644 (file)
@@ -672,7 +672,7 @@ int drm_close(struct dev_close_args *ap)
            !dev->driver->reclaim_buffers_locked)
                drm_reclaim_buffers(dev, file_priv);
 
-       funsetown(dev->buf_sigio);
+       funsetown(&dev->buf_sigio);
 
        if (dev->driver->postclose != NULL)
                dev->driver->postclose(dev, file_priv);
index 6f23c8c..b78b7b2 100644 (file)
@@ -573,6 +573,7 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
     mouse_info_t *mouse;
     scr_stat *cur_scp;
     scr_stat *scp;
+    struct proc *oproc;
     int f;
 
     scp = SC_STAT(tp->t_dev);
@@ -586,15 +587,21 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
        switch (mouse->operation) {
        case MOUSE_MODE:
            if (ISSIGVALID(mouse->u.mode.signal)) {
+               oproc = scp->mouse_proc;
                scp->mouse_signal = mouse->u.mode.signal;
                scp->mouse_proc = curproc;
                scp->mouse_pid = curproc->p_pid;
-           }
-           else {
+               PHOLD(curproc);
+           } else {
+               oproc = scp->mouse_proc;
                scp->mouse_signal = 0;
                scp->mouse_proc = NULL;
                scp->mouse_pid = 0;
            }
+           if (oproc) {
+                   PRELE(oproc);
+                   oproc = NULL;
+           }
            return 0;
 
        case MOUSE_SHOW:
@@ -688,10 +695,13 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
            if (cur_scp->mouse_signal) {
                /* has controlling process died? */
                if (cur_scp->mouse_proc && 
-                   (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
+                   (cur_scp->mouse_proc != pfindn(cur_scp->mouse_pid))){
+                       oproc = cur_scp->mouse_proc;
                        cur_scp->mouse_signal = 0;
                        cur_scp->mouse_proc = NULL;
                        cur_scp->mouse_pid = 0;
+                       if (oproc)
+                               PRELE(oproc);
                } else {
                    ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
                    break;
@@ -741,10 +751,13 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
            if (cur_scp->mouse_signal) {
                if (cur_scp->mouse_proc && 
-                   (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
+                   (cur_scp->mouse_proc != pfindn(cur_scp->mouse_pid))){
+                       oproc = cur_scp->mouse_proc;
                        cur_scp->mouse_signal = 0;
                        cur_scp->mouse_proc = NULL;
                        cur_scp->mouse_pid = 0;
+                       if (oproc)
+                               PRELE(oproc);
                } else {
                    ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
                    break;
index 90b558c..8695716 100644 (file)
@@ -963,7 +963,7 @@ scioctl(struct dev_ioctl_args *ap)
        DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
        if (scp->smode.mode == VT_PROCESS) {
            lwkt_gettoken(&proc_token);
-           if (scp->proc == pfind(scp->pid) && scp->proc != curproc) {
+           if (scp->proc == pfindn(scp->pid) && scp->proc != curproc) {
                DPRINTF(5, ("error EPERM\n"));
                lwkt_reltoken(&proc_token);
                lwkt_reltoken(&tty_token);
@@ -2353,7 +2353,7 @@ sc_switch_scr(sc_softc_t *sc, u_int next_scr)
        cur_scp->proc &&
        lwkt_trytoken(&proc_token)) {
 
-       if (cur_scp->proc != pfind(cur_scp->pid)) {
+       if (cur_scp->proc != pfindn(cur_scp->pid)) {
            /* 
             * The controlling process has died!!.  Do some clean up.
             * NOTE:`cur_scp->proc' and `cur_scp->smode.mode' 
@@ -2556,7 +2556,7 @@ vt_proc_alive(scr_stat *scp)
     lwkt_gettoken(&tty_token);
     lwkt_gettoken(&proc_token);
     if (scp->proc) {
-       if (scp->proc == pfind(scp->pid)) {
+       if (scp->proc == pfindn(scp->pid)) {
            lwkt_reltoken(&proc_token);
            lwkt_reltoken(&tty_token);
            return TRUE;
index 9651229..488c5c2 100644 (file)
@@ -128,7 +128,7 @@ struct reg;
 struct fpreg;
 struct dbreg;
 
-#define PFIND(pid) ((pid) ? pfind(pid) : &proc0)
+#define PFIND(pid) ((pid) ? pfindn(pid) : &proc0) /* pfindn() not MPSAFE XXX */
 
 void linprocfs_init (void);
 void linprocfs_exit (struct thread *);
index 4097a0f..e385198 100644 (file)
@@ -228,6 +228,7 @@ linprocfs_close(struct vop_close_args *ap)
                 * told to stop on an event, but then the requesting process
                 * has gone away or forgotten about it.
                 */
+               p = NULL;
                if ((ap->a_vp->v_opencount < 2)
                    && (p = pfind(pfs->pfs_pid))
                    && !(p->p_pfsflags & PF_LINGER)) {
@@ -235,6 +236,8 @@ linprocfs_close(struct vop_close_args *ap)
                        p->p_step = 0;
                        wakeup(&p->p_step);
                }
+               if (p)
+                       PRELE(p);
                break;
        default:
                break;
@@ -261,8 +264,10 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
                return ENOTTY;
        }
 
-       if (p_trespass(ap->a_cred, procp->p_ucred))
-               return EPERM;
+       if (p_trespass(ap->a_cred, procp->p_ucred)) {
+               error = EPERM;
+               goto done;
+       }
 
        switch (ap->a_command) {
        case PIOCBIS:
@@ -279,7 +284,7 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
 #define NFLAGS (PF_ISUGID)
          flags = (unsigned char)*(unsigned int*)ap->a_data;
          if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)))
-           return error;
+           goto done;
          procp->p_pfsflags = flags;
          break;
        case PIOCGFL:
@@ -301,7 +306,7 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
          if (procp->p_step == 0) {
            error = tsleep(&procp->p_stype, PCATCH, "piocwait", 0);
            if (error)
-             return error;
+             goto done;
          }
          psp->state = 1;       /* It stopped */
          psp->flags = procp->p_pfsflags;
@@ -310,20 +315,29 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
          psp->val = procp->p_xstat;    /* any extra info */
          break;
        case PIOCCONT:  /* Restart a proc */
-         if (procp->p_step == 0)
-           return EINVAL;      /* Can only start a stopped process */
+         if (procp->p_step == 0) {
+           error = EINVAL;     /* Can only start a stopped process */
+           goto done;
+         }
          if ((signo = *(int*)ap->a_data) != 0) {
-           if (signo >= NSIG || signo <= 0)
-             return EINVAL;
+           if (signo >= NSIG || signo <= 0) {
+             error = EINVAL;
+             goto done;
+           }
            ksignal(procp, signo);
          }
          procp->p_step = 0;
          wakeup(&procp->p_step);
          break;
        default:
-         return (ENOTTY);
+         error = ENOTTY;
+         goto done;
        }
-       return 0;
+       error = 0;
+done:
+       if (procp)
+               PRELE(procp);
+       return error;
 }
 
 /*
@@ -428,7 +442,7 @@ linprocfs_getattr(struct vop_getattr_args *ap)
        switch (pfs->pfs_type) {
        case Proot:
        case Pself:
-               procp = 0;
+               procp = NULL;
                break;
 
        default:
index 1229570..0c30fb5 100644 (file)
@@ -421,10 +421,10 @@ sys_linux_exit_group(struct linux_exit_group_args *args)
                LIST_INSERT_AFTER(e, em, threads);
                if ((e->flags & EMUL_DIDKILL) == 0) {
                        e->flags |= EMUL_DIDKILL;
-                       KKASSERT(pfind(e->proc->p_pid) == e->proc);
-                       get_mplock();
+                       lwkt_gettoken(&proc_token);
+                       KKASSERT(pfindn(e->proc->p_pid) == e->proc);
                        ksignal(e->proc, SIGKILL);
-                       rel_mplock();
+                       lwkt_reltoken(&proc_token);
                }
        }
 
index daf28ff..21622f7 100644 (file)
@@ -266,6 +266,7 @@ sys_linux_ptrace(struct linux_ptrace_args *uap)
        void *addr;
        pid_t pid;
        int error, req;
+       struct proc *p = NULL;  /* held process */
 
        error = 0;
 
@@ -498,5 +499,10 @@ sys_linux_ptrace(struct linux_ptrace_args *uap)
                break;
        }
 
+       /*
+        * Release held proces (if any) before returning.
+        */
+       if (p)
+               PRELE(p);
        return (error);
 }
index 08d2ae2..f67c451 100644 (file)
@@ -719,10 +719,10 @@ sys_linux_get_robust_list(struct linux_get_robust_list_args *args)
                if (priv_check(curthread, PRIV_CRED_SETUID) ||
                    priv_check(curthread, PRIV_CRED_SETEUID)/* ||
                    p_candebug(curproc, p) */) {
+                       PRELE(p);
                        return (EPERM);
                }
-               
-
+               PRELE(p);
        }
 
        error = copyout(&len, args->len, sizeof(l_size_t));
index 4094829..336fb7d 100644 (file)
@@ -1705,6 +1705,7 @@ sys_linux_getppid(struct linux_getppid_args *args)
        } else {
                args->sysmsg_result = parent->p_pid;
        }
+       PRELE(p);
 
 out:
        return (0);
@@ -1840,6 +1841,7 @@ sys_linux_sched_getaffinity(struct linux_sched_getaffinity_args *args)
        get_mplock();
        if (args->pid == 0) {
                p = curproc;
+               PHOLD(p);
        } else {
                p = pfind(args->pid);
                if (p == NULL) {
@@ -1862,6 +1864,8 @@ done:
        if (error == 0)
                args->sysmsg_iresult = sizeof(cpumask_t);
 #endif
+       if (p)
+               PRELE(p);
        return (error);
 }
 
index 1b4ddc2..2f97b33 100644 (file)
@@ -415,7 +415,6 @@ linux_do_tkill(l_int tgid, l_int pid, l_int sig)
                        goto done2;
                }
        }
-       PHOLD(p);
 
        EMUL_LOCK();
        em = emuldata_get(p);
index 90b398c..7760075 100644 (file)
@@ -64,6 +64,7 @@
 #include <sys/malloc.h>
 #include <sys/machintr.h>
 
+#include <sys/refcount.h>
 #include <sys/file2.h>
 #include <sys/thread2.h>
 #include <sys/sysref2.h>
@@ -370,15 +371,20 @@ proc0_init(void *dummy __unused)
         * Create process 0 (the swapper).
         */
        LIST_INSERT_HEAD(&allproc, p, p_list);
-       p->p_pgrp = &pgrp0;
        LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash);
        LIST_INIT(&pgrp0.pg_members);
+       lwkt_token_init(&pgrp0.pg_token, "pgrp0");
+       refcount_init(&pgrp0.pg_refs, 1);
+       lockinit(&pgrp0.pg_lock, "pgwt0", 0, 0);
        LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist);
 
        pgrp0.pg_session = &session0;
        session0.s_count = 1;
        session0.s_leader = p;
 
+       pgref(&pgrp0);
+       p->p_pgrp = &pgrp0;
+
        p->p_sysent = &aout_sysvec;
 
        p->p_flag = P_SYSTEM;
index 9c469a3..f38aeaf 100644 (file)
@@ -645,26 +645,46 @@ retry:
  * MPSAFE
  */
 void
-funsetown(struct sigio *sigio)
+funsetown(struct sigio **sigiop)
 {
+       struct pgrp *pgrp;
+       struct proc *p;
+       struct sigio *sigio;
+
+       if ((sigio = *sigiop) != NULL) {
+               lwkt_gettoken(&proc_token);     /* protect sigio */
+               KKASSERT(sigiop == sigio->sio_myref);
+               sigio = *sigiop;
+               *sigiop = NULL;
+               lwkt_reltoken(&proc_token);
+       }
        if (sigio == NULL)
                return;
-       lwkt_gettoken(&proc_token);
-       *(sigio->sio_myref) = NULL;
+
        if (sigio->sio_pgid < 0) {
-               SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
-                            sigio, sio_pgsigio);
+               pgrp = sigio->sio_pgrp;
+               sigio->sio_pgrp = NULL;
+               lwkt_gettoken(&pgrp->pg_token);
+               SLIST_REMOVE(&pgrp->pg_sigiolst, sigio, sigio, sio_pgsigio);
+               lwkt_reltoken(&pgrp->pg_token);
+               pgrel(pgrp);
        } else /* if ((*sigiop)->sio_pgid > 0) */ {
-               SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
-                            sigio, sio_pgsigio);
+               p = sigio->sio_proc;
+               sigio->sio_proc = NULL;
+               PHOLD(p);
+               lwkt_gettoken(&p->p_token);
+               SLIST_REMOVE(&p->p_sigiolst, sigio, sigio, sio_pgsigio);
+               lwkt_reltoken(&p->p_token);
+               PRELE(p);
        }
-       lwkt_reltoken(&proc_token);
        crfree(sigio->sio_ucred);
+       sigio->sio_ucred = NULL;
        kfree(sigio, M_SIGIO);
 }
 
 /*
- * Free a list of sigio structures.
+ * Free a list of sigio structures.  Caller is responsible for ensuring
+ * that the list is MPSAFE.
  *
  * MPSAFE
  */
@@ -673,10 +693,8 @@ funsetownlst(struct sigiolst *sigiolst)
 {
        struct sigio *sigio;
 
-       lwkt_gettoken(&proc_token);
        while ((sigio = SLIST_FIRST(sigiolst)) != NULL)
-               funsetown(sigio);
-       lwkt_reltoken(&proc_token);
+               funsetown(sigio->sio_myref);
 }
 
 /*
@@ -690,17 +708,16 @@ funsetownlst(struct sigiolst *sigiolst)
 int
 fsetown(pid_t pgid, struct sigio **sigiop)
 {
-       struct proc *proc;
-       struct pgrp *pgrp;
+       struct proc *proc = NULL;
+       struct pgrp *pgrp = NULL;
        struct sigio *sigio;
        int error;
 
        if (pgid == 0) {
-               funsetown(*sigiop);
+               funsetown(sigiop);
                return (0);
        }
 
-       lwkt_gettoken(&proc_token);
        if (pgid > 0) {
                proc = pfind(pgid);
                if (proc == NULL) {
@@ -720,8 +737,6 @@ fsetown(pid_t pgid, struct sigio **sigiop)
                        error = EPERM;
                        goto done;
                }
-
-               pgrp = NULL;
        } else /* if (pgid < 0) */ {
                pgrp = pgfind(-pgid);
                if (pgrp == NULL) {
@@ -741,27 +756,39 @@ fsetown(pid_t pgid, struct sigio **sigiop)
                        error = EPERM;
                        goto done;
                }
-
-               proc = NULL;
        }
-       funsetown(*sigiop);
-       sigio = kmalloc(sizeof(struct sigio), M_SIGIO, M_WAITOK);
+       sigio = kmalloc(sizeof(struct sigio), M_SIGIO, M_WAITOK | M_ZERO);
        if (pgid > 0) {
+               KKASSERT(pgrp == NULL);
+               lwkt_gettoken(&proc->p_token);
                SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio);
                sigio->sio_proc = proc;
+               lwkt_reltoken(&proc->p_token);
        } else {
+               KKASSERT(proc == NULL);
+               lwkt_gettoken(&pgrp->pg_token);
                SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio);
                sigio->sio_pgrp = pgrp;
+               lwkt_reltoken(&pgrp->pg_token);
+               pgrp = NULL;
        }
        sigio->sio_pgid = pgid;
        sigio->sio_ucred = crhold(curthread->td_ucred);
        /* It would be convenient if p_ruid was in ucred. */
        sigio->sio_ruid = sigio->sio_ucred->cr_ruid;
        sigio->sio_myref = sigiop;
+
+       lwkt_gettoken(&proc_token);
+       while (*sigiop)
+               funsetown(sigiop);
        *sigiop = sigio;
+       lwkt_reltoken(&proc_token);
        error = 0;
 done:
-       lwkt_reltoken(&proc_token);
+       if (pgrp)
+               pgrel(pgrp);
+       if (proc)
+               PRELE(proc);
        return (error);
 }
 
index f50bfd3..6bc8158 100644 (file)
@@ -209,21 +209,21 @@ filt_procattach(struct knote *kn)
        int immediate;
 
        immediate = 0;
-       lwkt_gettoken(&proc_token);
        p = pfind(kn->kn_id);
        if (p == NULL && (kn->kn_sfflags & NOTE_EXIT)) {
                p = zpfind(kn->kn_id);
                immediate = 1;
        }
        if (p == NULL) {
-               lwkt_reltoken(&proc_token);
                return (ESRCH);
        }
        if (!PRISON_CHECK(curthread->td_ucred, p->p_ucred)) {
-               lwkt_reltoken(&proc_token);
+               if (p)
+                       PRELE(p);
                return (EACCES);
        }
 
+       lwkt_gettoken(&p->p_token);
        kn->kn_ptr.p_proc = p;
        kn->kn_flags |= EV_CLEAR;               /* automatically set */
 
@@ -245,7 +245,8 @@ filt_procattach(struct knote *kn)
         */
        if (immediate && filt_proc(kn, NOTE_EXIT))
                KNOTE_ACTIVATE(kn);
-       lwkt_reltoken(&proc_token);
+       lwkt_reltoken(&p->p_token);
+       PRELE(p);
 
        return (0);
 }
@@ -1200,7 +1201,7 @@ kqueue_close(struct file *fp)
        kqueue_terminate(kq);
 
        fp->f_data = NULL;
-       funsetown(kq->kq_sigio);
+       funsetown(&kq->kq_sigio);
 
        kfree(kq, M_KQUEUE);
        return (0);
index c6f6125..e577e1d 100644 (file)
@@ -521,29 +521,34 @@ exit1(int rv)
         */
        if (p->p_pptr->p_sigacts->ps_flag & PS_NOCLDWAIT) {
                struct proc *pp = p->p_pptr;
+
+               PHOLD(pp);
+               lwkt_gettoken(&pp->p_token);
                proc_reparent(p, initproc);
+
                /*
                 * If this was the last child of our parent, notify
                 * parent, so in case he was wait(2)ing, he will
-                * continue.
+                * continue.  This function interlocks with pptr->p_token.
                 */
                if (LIST_EMPTY(&pp->p_children))
                        wakeup((caddr_t)pp);
+               lwkt_reltoken(&pp->p_token);
+               PRELE(pp);
        }
 
        /* lwkt_gettoken(&proc_token); */
        q = p->p_pptr;
+       PHOLD(q);
        if (p->p_sigparent && q != initproc) {
-               PHOLD(q);
                ksignal(q, p->p_sigparent);
-               PRELE(q);
        } else {
                ksignal(q, SIGCHLD);
        }
+       wakeup(p->p_pptr);
+       PRELE(q);
        /* lwkt_reltoken(&proc_token); */
        /* NOTE: p->p_pptr can get ripped out */
-
-       wakeup(p->p_pptr);
        /*
         * cpu_exit is responsible for clearing curproc, since
         * it is heavily integrated with the thread/switching sequence.
@@ -866,12 +871,13 @@ loop:
                         * If we got the child via a ptrace 'attach',
                         * we need to give it back to the old parent.
                         */
-                       if (p->p_oppid && (t = pfind(p->p_oppid))) {
+                       if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) {
                                p->p_oppid = 0;
                                proc_reparent(p, t);
                                ksignal(t, SIGCHLD);
                                wakeup((caddr_t)t);
                                error = 0;
+                               PRELE(t);
                                goto done;
                        }
 
@@ -948,7 +954,11 @@ loop:
                error = 0;
                goto done;
        }
-       error = tsleep((caddr_t)q, PCATCH, "wait", 0);
+
+       /*
+        * Wait for signal - interlocked using q->p_token.
+        */
+       error = tsleep(q, PCATCH, "wait", 0);
        if (error) {
 done:
                lwkt_reltoken(&q->p_token);
index 89a8658..95153cc 100644 (file)
@@ -236,7 +236,8 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
 {
        struct proc *p1 = lp1->lwp_proc;
        struct proc *p2, *pptr;
-       struct pgrp *pgrp;
+       struct pgrp *p1grp;
+       struct pgrp *plkgrp;
        uid_t uid;
        int ok, error;
        static int curfail = 0;
@@ -248,7 +249,7 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
                return (EINVAL);
 
        lwkt_gettoken(&p1->p_token);
-       pgrp = NULL;
+       plkgrp = NULL;
 
        /*
         * Here we don't create a new process, but we divorce
@@ -300,8 +301,10 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
         * and cause the process group lock to be held indefinitely.  If
         * a STOP occurs, the fork will be restarted after the CONT.
         */
-       if ((flags & RFPGLOCK) && (pgrp = p1->p_pgrp) != NULL) {
-               lockmgr(&pgrp->pg_lock, LK_SHARED);
+       p1grp = p1->p_pgrp;
+       if ((flags & RFPGLOCK) && (plkgrp = p1->p_pgrp) != NULL) {
+               pgref(plkgrp);
+               lockmgr(&plkgrp->pg_lock, LK_SHARED);
                if (CURSIG_NOBLOCK(lp1)) {
                        error = ERESTART;
                        goto done;
@@ -483,7 +486,10 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
         * race a ^C being sent to the process group by not receiving it
         * at all prior to this line.
         */
+       pgref(p1grp);
+       lwkt_gettoken(&p1grp->pg_token);
        LIST_INSERT_AFTER(p1, p2, p_pglist);
+       lwkt_reltoken(&p1grp->pg_token);
 
        /*
         * Attach the new process to its parent.
@@ -578,8 +584,10 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
        error = 0;
 done:
        lwkt_reltoken(&p1->p_token);
-       if (pgrp)
-               lockmgr(&pgrp->pg_lock, LK_RELEASE);
+       if (plkgrp) {
+               lockmgr(&plkgrp->pg_lock, LK_RELEASE);
+               pgrel(plkgrp);
+       }
        return (error);
 }
 
index d159143..3f63bbd 100644 (file)
@@ -299,19 +299,25 @@ sys_ktrace(struct ktrace_args *uap)
         */
        if (uap->pid < 0) {
                /*
-                * by process group
+                * By process group.  Process group is referenced, preventing
+                * disposal.
                 */
                pg = pgfind(-uap->pid);
                if (pg == NULL) {
                        error = ESRCH;
                        goto done;
                }
+               lwkt_gettoken(&pg->pg_token);
                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
+                       PHOLD(p);
                        if (descend)
                                ret |= ktrsetchildren(td, p, ops, facs, tracenode);
                        else
                                ret |= ktrops(td, p, ops, facs, tracenode);
+                       PRELE(p);
                }
+               lwkt_reltoken(&pg->pg_token);
+               pgrel(pg);
        } else {
                /*
                 * by pid
@@ -325,6 +331,7 @@ sys_ktrace(struct ktrace_args *uap)
                        ret |= ktrsetchildren(td, p, ops, facs, tracenode);
                else
                        ret |= ktrops(td, p, ops, facs, tracenode);
+               PRELE(p);
        }
        if (!ret)
                error = EPERM;
index bf4acbe..75d8014 100644 (file)
@@ -90,22 +90,26 @@ int p31b_proc(struct proc *p, pid_t pid, struct proc **pp)
        int ret = 0;
        struct proc *other_proc = 0;
 
-       if (pid == 0)
+       if (pid == 0) {
                other_proc = p;
-       else
+               if (other_proc)
+                       PHOLD(other_proc);
+       } else {
                other_proc = pfind(pid);
+               /* ref from pfind() */
+       }
 
-       if (other_proc)
-       {
+       if (other_proc) {
                /* Enforce permission policy.
                 */
                if (CAN_AFFECT(p, p->p_ucred, other_proc))
                        *pp = other_proc;
                else
                        ret = EPERM;
-       }
-       else
+               PRELE(other_proc);
+       } else {
                ret = ESRCH;
+       }
 
        return ret;
 }
index 62bc488..71b2d0b 100644 (file)
@@ -56,6 +56,7 @@
 #include <sys/user.h>
 #include <machine/smp.h>
 
+#include <sys/refcount.h>
 #include <sys/spinlock2.h>
 #include <sys/mplock2.h>
 
@@ -161,12 +162,10 @@ inferior(struct proc *p)
 }
 
 /*
- * Locate a process by number
- *
- * XXX TODO - change API to PHOLD() the returned process ?
+ * Locate a process by number.  The returned process will be referenced and
+ * must be released with PRELE().
  *
  * No requirements.
- * The caller must hold proc_token if the caller wishes a stable result.
  */
 struct proc *
 pfind(pid_t pid)
@@ -176,6 +175,7 @@ pfind(pid_t pid)
        lwkt_gettoken(&proc_token);
        LIST_FOREACH(p, PIDHASH(pid), p_hash) {
                if (p->p_pid == pid) {
+                       PHOLD(p);
                        lwkt_reltoken(&proc_token);
                        return (p);
                }
@@ -185,10 +185,46 @@ pfind(pid_t pid)
 }
 
 /*
- * Locate a process group by number
+ * Locate a process by number.  The returned process is NOT referenced.
+ * The caller should hold proc_token if the caller wishes a stable result.
+ *
+ * No requirements.
+ */
+struct proc *
+pfindn(pid_t pid)
+{
+       struct proc *p;
+
+       lwkt_gettoken(&proc_token);
+       LIST_FOREACH(p, PIDHASH(pid), p_hash) {
+               if (p->p_pid == pid) {
+                       lwkt_reltoken(&proc_token);
+                       return (p);
+               }
+       }
+       lwkt_reltoken(&proc_token);
+       return (NULL);
+}
+
+void
+pgref(struct pgrp *pgrp)
+{
+       refcount_acquire(&pgrp->pg_refs);
+}
+
+void
+pgrel(struct pgrp *pgrp)
+{
+       if (refcount_release(&pgrp->pg_refs))
+               pgdelete(pgrp);
+}
+
+/*
+ * Locate a process group by number.  The returned process group will be
+ * referenced w/pgref() and must be released with pgrel() (or assigned
+ * somewhere if you wish to keep the reference).
  *
  * No requirements.
- * The caller must hold proc_token if the caller wishes a stable result.
  */
 struct pgrp *
 pgfind(pid_t pgid)
@@ -198,6 +234,7 @@ pgfind(pid_t pgid)
        lwkt_gettoken(&proc_token);
        LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) {
                if (pgrp->pg_id == pgid) {
+                       refcount_acquire(&pgrp->pg_refs);
                        lwkt_reltoken(&proc_token);
                        return (pgrp);
                }
@@ -215,9 +252,9 @@ int
 enterpgrp(struct proc *p, pid_t pgid, int mksess)
 {
        struct pgrp *pgrp;
+       struct pgrp *opgrp;
        int error;
 
-       lwkt_gettoken(&proc_token);
        pgrp = pgfind(pgid);
 
        KASSERT(pgrp == NULL || !mksess,
@@ -233,7 +270,7 @@ enterpgrp(struct proc *p, pid_t pgid, int mksess)
                 */
                KASSERT(p->p_pid == pgid,
                        ("enterpgrp: new pgrp and pid != pgid"));
-               if ((np = pfind(savepid)) == NULL || np != p) {
+               if ((np = pfindn(savepid)) == NULL || np != p) {
                        error = ESRCH;
                        goto fatal;
                }
@@ -267,28 +304,38 @@ enterpgrp(struct proc *p, pid_t pgid, int mksess)
                LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
                pgrp->pg_jobc = 0;
                SLIST_INIT(&pgrp->pg_sigiolst);
+               lwkt_token_init(&pgrp->pg_token, "pgrp_token");
+               refcount_init(&pgrp->pg_refs, 1);
                lockinit(&pgrp->pg_lock, "pgwt", 0, 0);
        } else if (pgrp == p->p_pgrp) {
+               pgrel(pgrp);
                goto done;
-       }
+       } /* else pgfind() referenced the pgrp */
 
        /*
         * Adjust eligibility of affected pgrps to participate in job control.
         * Increment eligibility counts before decrementing, otherwise we
         * could reach 0 spuriously during the first call.
         */
+       lwkt_gettoken(&pgrp->pg_token);
+       lwkt_gettoken(&p->p_token);
        fixjobc(p, pgrp, 1);
        fixjobc(p, p->p_pgrp, 0);
-
-       LIST_REMOVE(p, p_pglist);
-       if (LIST_EMPTY(&p->p_pgrp->pg_members))
-               pgdelete(p->p_pgrp);
+       while ((opgrp = p->p_pgrp) != NULL) {
+               opgrp = p->p_pgrp;
+               lwkt_gettoken(&opgrp->pg_token);
+               LIST_REMOVE(p, p_pglist);
+               p->p_pgrp = NULL;
+               lwkt_reltoken(&opgrp->pg_token);
+               pgrel(opgrp);
+       }
        p->p_pgrp = pgrp;
        LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
+       lwkt_reltoken(&p->p_token);
+       lwkt_reltoken(&pgrp->pg_token);
 done:
        error = 0;
 fatal:
-       lwkt_reltoken(&proc_token);
        return (error);
 }
 
@@ -300,19 +347,30 @@ fatal:
 int
 leavepgrp(struct proc *p)
 {
-       lwkt_gettoken(&proc_token);
-       LIST_REMOVE(p, p_pglist);
-       if (LIST_EMPTY(&p->p_pgrp->pg_members))
-               pgdelete(p->p_pgrp);
-       p->p_pgrp = NULL;
-       lwkt_reltoken(&proc_token);
+       struct pgrp *pg = p->p_pgrp;
+
+       lwkt_gettoken(&p->p_token);
+       pg = p->p_pgrp;
+       if (pg) {
+               pgref(pg);
+               lwkt_gettoken(&pg->pg_token);
+               if (p->p_pgrp == pg) {
+                       p->p_pgrp = NULL;
+                       LIST_REMOVE(p, p_pglist);
+                       pgrel(pg);
+               }
+               lwkt_reltoken(&pg->pg_token);
+               lwkt_reltoken(&p->p_token);     /* avoid chaining on rel */
+               pgrel(pg);
+       } else {
+               lwkt_reltoken(&p->p_token);
+       }
        return (0);
 }
 
 /*
- * Delete a process group
- *
- * The caller must hold proc_token.
+ * Delete a process group.  Must be called only after the last ref has been
+ * released.
  */
 static void
 pgdelete(struct pgrp *pgrp)
@@ -400,8 +458,8 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
         * Check p's parent to see whether p qualifies its own process
         * group; if so, adjust count for p's process group.
         */
-       lwkt_gettoken(&proc_token);
        lwkt_gettoken(&p->p_token);     /* p_children scan */
+       lwkt_gettoken(&pgrp->pg_token);
 
        mysession = pgrp->pg_session;
        if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
@@ -418,17 +476,26 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
         * process groups.
         */
        LIST_FOREACH(np, &p->p_children, p_sibling) {
+               PHOLD(np);
+               lwkt_gettoken(&np->p_token);
                if ((hispgrp = np->p_pgrp) != pgrp &&
                    hispgrp->pg_session == mysession &&
                    np->p_stat != SZOMB) {
+                       pgref(hispgrp);
+                       lwkt_gettoken(&hispgrp->pg_token);
                        if (entering)
                                hispgrp->pg_jobc++;
                        else if (--hispgrp->pg_jobc == 0)
                                orphanpg(hispgrp);
+                       lwkt_reltoken(&hispgrp->pg_token);
+                       pgrel(hispgrp);
                }
+               lwkt_reltoken(&np->p_token);
+               PRELE(np);
        }
+       KKASSERT(pgrp->pg_refs > 0);
+       lwkt_reltoken(&pgrp->pg_token);
        lwkt_reltoken(&p->p_token);
-       lwkt_reltoken(&proc_token);
 }
 
 /*
@@ -436,7 +503,7 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
  * if there are any stopped processes in the group,
  * hang-up all process in that group.
  *
- * The caller must hold proc_token.
+ * The caller must hold pg_token.
  */
 static void
 orphanpg(struct pgrp *pg)
@@ -700,8 +767,9 @@ DB_SHOW_COMMAND(pgrpdump, pgrpdump)
 
 /*
  * Locate a process on the zombie list.  Return a process or NULL.
+ * The returned process will be referenced and the caller must release
+ * it with PRELE().
  *
- * The caller must hold proc_token if a stable result is desired.
  * No other requirements.
  */
 struct proc *
@@ -712,6 +780,7 @@ zpfind(pid_t pid)
        lwkt_gettoken(&proc_token);
        LIST_FOREACH(p, &zombproc, p_list) {
                if (p->p_pid == pid) {
+                       PHOLD(p);
                        lwkt_reltoken(&proc_token);
                        return (p);
                }
@@ -797,7 +866,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 
        lwkt_gettoken(&proc_token);
        if (oid == KERN_PROC_PID) {
-               p = pfind((pid_t)name[0]);
+               p = pfindn((pid_t)name[0]);
                if (p == NULL)
                        goto post_threads;
                if (!PRISON_CHECK(cr1, p->p_ucred))
@@ -941,7 +1010,7 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARGS)
                return (EINVAL);
 
        lwkt_gettoken(&proc_token);
-       p = pfind((pid_t)name[0]);
+       p = pfindn((pid_t)name[0]);
        if (p == NULL)
                goto done;
 
@@ -1001,7 +1070,7 @@ sysctl_kern_proc_cwd(SYSCTL_HANDLER_ARGS)
                return (EINVAL);
 
        lwkt_gettoken(&proc_token);
-       p = pfind((pid_t)name[0]);
+       p = pfindn((pid_t)name[0]);
        if (p == NULL)
                goto done;
 
index 3811f19..a48ca4f 100644 (file)
@@ -128,19 +128,21 @@ sys_getpgid(struct getpgid_args *uap)
        struct proc *pt;
        int error;
 
-       lwkt_gettoken(&proc_token);
        error = 0;
 
        if (uap->pid == 0) {
                pt = p;
+               PHOLD(pt);
        } else {
                pt = pfind(uap->pid);
                if (pt == NULL)
                        error = ESRCH;
        }
+       /* XXX MPSAFE on pgrp? */
        if (error == 0)
                uap->sysmsg_result = pt->p_pgrp->pg_id;
-       lwkt_reltoken(&proc_token);
+       if (pt)
+               PRELE(pt);
        return (error);
 }
 
@@ -154,11 +156,11 @@ sys_getsid(struct getsid_args *uap)
        struct proc *pt;
        int error;
 
-       lwkt_gettoken(&proc_token);
        error = 0;
 
        if (uap->pid == 0) {
                pt = p;
+               PHOLD(pt);
        } else {
                pt = pfind(uap->pid);
                if (pt == NULL)
@@ -166,7 +168,8 @@ sys_getsid(struct getsid_args *uap)
        }
        if (error == 0)
                uap->sysmsg_result = pt->p_session->s_sid;
-       lwkt_reltoken(&proc_token);
+       if (pt)
+               PRELE(pt);
        return (error);
 }
 
@@ -264,17 +267,20 @@ int
 sys_setsid(struct setsid_args *uap)
 {
        struct proc *p = curproc;
+       struct pgrp *pg = NULL;
        int error;
 
-       lwkt_gettoken(&proc_token);
-       if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
+       lwkt_gettoken(&p->p_token);
+       if (p->p_pgid == p->p_pid || (pg = pgfind(p->p_pid)) != NULL) {
                error = EPERM;
+               if (pg)
+                       pgrel(pg);
        } else {
                enterpgrp(p, p->p_pid, 1);
                uap->sysmsg_result = p->p_pid;
                error = 0;
        }
-       lwkt_reltoken(&proc_token);
+       lwkt_reltoken(&p->p_token);
        return (error);
 }
 
@@ -296,18 +302,23 @@ sys_setpgid(struct setpgid_args *uap)
 {
        struct proc *curp = curproc;
        struct proc *targp;             /* target process */
-       struct pgrp *pgrp;              /* target pgrp */
+       struct pgrp *pgrp = NULL;       /* target pgrp */
        int error;
 
        if (uap->pgid < 0)
                return (EINVAL);
 
-       lwkt_gettoken(&proc_token);
        if (uap->pid != 0 && uap->pid != curp->p_pid) {
-               if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) {
+               if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
+                       if (targp)
+                               PRELE(targp);
                        error = ESRCH;
+                       targp = NULL;
                        goto done;
                }
+               lwkt_gettoken(&targp->p_token);
+               /* targp now referenced and its token is held */
+
                if (targp->p_pgrp == NULL ||
                    targp->p_session != curp->p_session) {
                        error = EPERM;
@@ -319,6 +330,8 @@ sys_setpgid(struct setpgid_args *uap)
                }
        } else {
                targp = curp;
+               PHOLD(targp);
+               lwkt_gettoken(&targp->p_token);
        }
        if (SESS_LEADER(targp)) {
                error = EPERM;
@@ -327,7 +340,7 @@ sys_setpgid(struct setpgid_args *uap)
        if (uap->pgid == 0) {
                uap->pgid = targp->p_pid;
        } else if (uap->pgid != targp->p_pid) {
-               if ((pgrp = pgfind(uap->pgid)) == 0 ||
+               if ((pgrp = pgfind(uap->pgid)) == NULL ||
                    pgrp->pg_session != curp->p_session) {
                        error = EPERM;
                        goto done;
@@ -335,7 +348,12 @@ sys_setpgid(struct setpgid_args *uap)
        }
        error = enterpgrp(targp, uap->pgid, 0);
 done:
-       lwkt_reltoken(&proc_token);
+       if (pgrp)
+               pgrel(pgrp);
+       if (targp) {
+               lwkt_reltoken(&targp->p_token);
+               PRELE(targp);
+       }
        return (error);
 }
 
index 1f6c0d5..afee45f 100644 (file)
@@ -63,7 +63,6 @@
 
 #include <sys/thread2.h>
 #include <sys/spinlock2.h>
-#include <sys/mplock2.h>
 
 static int donice (struct proc *chgp, int n);
 static int doionice (struct proc *chgp, int n);
@@ -100,33 +99,40 @@ sys_getpriority(struct getpriority_args *uap)
        int low = PRIO_MAX + 1;
        int error;
 
-       get_mplock();
-
        switch (uap->which) {
        case PRIO_PROCESS:
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        p = curp;
-               else
+                       PHOLD(p);
+               } else {
                        p = pfind(uap->who);
-               if (p == 0)
-                       break;
-               if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
-                       break;
-               low = p->p_nice;
+               }
+               if (p) {
+                       if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
+                               low = p->p_nice;
+                       }
+                       PRELE(p);
+               }
                break;
 
        case PRIO_PGRP: 
        {
                struct pgrp *pg;
 
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        pg = curp->p_pgrp;
-               else if ((pg = pgfind(uap->who)) == NULL)
+                       pgref(pg);
+               } else if ((pg = pgfind(uap->who)) == NULL) {
                        break;
+               } /* else ref held from pgfind */
+
                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
-                       if ((PRISON_CHECK(curp->p_ucred, p->p_ucred) && p->p_nice < low))
+                       if (PRISON_CHECK(curp->p_ucred, p->p_ucred) &&
+                           p->p_nice < low) {
                                low = p->p_nice;
+                       }
                }
+               pgrel(pg);
                break;
        }
        case PRIO_USER:
@@ -149,7 +155,6 @@ sys_getpriority(struct getpriority_args *uap)
        uap->sysmsg_result = low;
        error = 0;
 done:
-       rel_mplock();
        return (error);
 }
 
@@ -191,36 +196,43 @@ sys_setpriority(struct setpriority_args *uap)
        struct proc *p;
        int found = 0, error = 0;
 
-       get_mplock();
+       lwkt_gettoken(&proc_token);
 
        switch (uap->which) {
        case PRIO_PROCESS:
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        p = curp;
-               else
+                       PHOLD(p);
+               } else {
                        p = pfind(uap->who);
-               if (p == 0)
-                       break;
-               if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
-                       break;
-               error = donice(p, uap->prio);
-               found++;
+               }
+               if (p) {
+                       if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
+                               error = donice(p, uap->prio);
+                               found++;
+                       }
+                       PRELE(p);
+               }
                break;
 
        case PRIO_PGRP: 
        {
                struct pgrp *pg;
 
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        pg = curp->p_pgrp;
-               else if ((pg = pgfind(uap->who)) == NULL)
+                       pgref(pg);
+               } else if ((pg = pgfind(uap->who)) == NULL) {
                        break;
+               } /* else ref held from pgfind */
+
                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                        if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
                                error = donice(p, uap->prio);
                                found++;
                        }
                }
+               pgrel(pg);
                break;
        }
        case PRIO_USER:
@@ -241,7 +253,8 @@ sys_setpriority(struct setpriority_args *uap)
                break;
        }
 
-       rel_mplock();
+       lwkt_reltoken(&proc_token);
+
        if (found == 0)
                error = ESRCH;
        return (error);
@@ -307,33 +320,40 @@ sys_ioprio_get(struct ioprio_get_args *uap)
        int high = IOPRIO_MIN-2;
        int error;
 
-       get_mplock();
+       lwkt_gettoken(&proc_token);
 
        switch (uap->which) {
        case PRIO_PROCESS:
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        p = curp;
-               else
+                       PHOLD(p);
+               } else {
                        p = pfind(uap->who);
-               if (p == 0)
-                       break;
-               if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
-                       break;
-               high = p->p_ionice;
+               }
+               if (p) {
+                       if (PRISON_CHECK(curp->p_ucred, p->p_ucred))
+                               high = p->p_ionice;
+                       PRELE(p);
+               }
                break;
 
        case PRIO_PGRP:
        {
                struct pgrp *pg;
 
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        pg = curp->p_pgrp;
-               else if ((pg = pgfind(uap->who)) == NULL)
+                       pgref(pg);
+               } else if ((pg = pgfind(uap->who)) == NULL) {
                        break;
+               } /* else ref held from pgfind */
+
                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
-                       if ((PRISON_CHECK(curp->p_ucred, p->p_ucred) && p->p_nice > high))
+                       if (PRISON_CHECK(curp->p_ucred, p->p_ucred) &&
+                           p->p_nice > high)
                                high = p->p_ionice;
                }
+               pgrel(pg);
                break;
        }
        case PRIO_USER:
@@ -356,7 +376,8 @@ sys_ioprio_get(struct ioprio_get_args *uap)
        uap->sysmsg_result = high;
        error = 0;
 done:
-       rel_mplock();
+       lwkt_reltoken(&proc_token);
+
        return (error);
 }
 
@@ -399,36 +420,43 @@ sys_ioprio_set(struct ioprio_set_args *uap)
        struct proc *p;
        int found = 0, error = 0;
 
-       get_mplock();
+       lwkt_gettoken(&proc_token);
 
        switch (uap->which) {
        case PRIO_PROCESS:
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        p = curp;
-               else
+                       PHOLD(p);
+               } else {
                        p = pfind(uap->who);
-               if (p == 0)
-                       break;
-               if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
-                       break;
-               error = doionice(p, uap->prio);
-               found++;
+               }
+               if (p) {
+                       if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
+                               error = doionice(p, uap->prio);
+                               found++;
+                       }
+                       PRELE(p);
+               }
                break;
 
        case PRIO_PGRP:
        {
                struct pgrp *pg;
 
-               if (uap->who == 0)
+               if (uap->who == 0) {
                        pg = curp->p_pgrp;
-               else if ((pg = pgfind(uap->who)) == NULL)
+                       pgref(pg);
+               } else if ((pg = pgfind(uap->who)) == NULL) {
                        break;
+               } /* else ref held from pgfind */
+
                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                        if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
                                error = doionice(p, uap->prio);
                                found++;
                        }
                }
+               pgrel(pg);
                break;
        }
        case PRIO_USER:
@@ -449,7 +477,8 @@ sys_ioprio_set(struct ioprio_set_args *uap)
                break;
        }
 
-       rel_mplock();
+       lwkt_reltoken(&proc_token);
+
        if (found == 0)
                error = ESRCH;
        return (error);
@@ -500,7 +529,7 @@ doionice(struct proc *chgp, int n)
 int
 sys_lwp_rtprio(struct lwp_rtprio_args *uap)
 {
-       struct proc *p = curproc;
+       struct proc *p;
        struct lwp *lp;
        struct rtprio rtp;
        struct ucred *cr = curthread->td_ucred;
@@ -512,9 +541,11 @@ sys_lwp_rtprio(struct lwp_rtprio_args *uap)
        if (uap->pid < 0)
                return EINVAL;
 
-       get_mplock();
+       lwkt_gettoken(&proc_token);
+
        if (uap->pid == 0) {
-               /* curproc already loaded on p */
+               p = curproc;
+               PHOLD(p);
        } else {
                p = pfind(uap->pid);
        }
@@ -599,7 +630,10 @@ sys_lwp_rtprio(struct lwp_rtprio_args *uap)
        }
 
 done:
-       rel_mplock();
+       if (p)
+               PRELE(p);
+       lwkt_reltoken(&proc_token);
+
        return (error);
 }
 
@@ -611,7 +645,6 @@ done:
 int
 sys_rtprio(struct rtprio_args *uap)
 {
-       struct proc *curp = curproc;
        struct proc *p;
        struct lwp *lp;
        struct ucred *cr = curthread->td_ucred;
@@ -622,11 +655,14 @@ sys_rtprio(struct rtprio_args *uap)
        if (error)
                return (error);
 
-       get_mplock();
-       if (uap->pid == 0)
-               p = curp;
-       else
+       lwkt_gettoken(&proc_token);
+
+       if (uap->pid == 0) {
+               p = curproc;
+               PHOLD(p);
+       } else {
                p = pfind(uap->pid);
+       }
 
        if (p == NULL) {
                error = ESRCH;
@@ -691,7 +727,10 @@ sys_rtprio(struct rtprio_args *uap)
                break;
        }
 done:
-       rel_mplock();
+       if (p)
+               PRELE(p);
+       lwkt_reltoken(&proc_token);
+
        return (error);
 }
 
@@ -805,7 +844,7 @@ sys_getrusage(struct getrusage_args *uap)
        struct rusage *rup;
        int error;
 
-       get_mplock();
+       lwkt_gettoken(&proc_token);
 
        switch (uap->who) {
        case RUSAGE_SELF:
@@ -823,7 +862,7 @@ sys_getrusage(struct getrusage_args *uap)
        }
        if (error == 0)
                error = copyout(rup, uap->rusage, sizeof(struct rusage));
-       rel_mplock();
+       lwkt_reltoken(&proc_token);
        return (error);
 }
 
index 61f21fe..0e241a5 100644 (file)
@@ -692,11 +692,16 @@ dokillpg(int sig, int pgid, int all)
                         * zero pgid means send to my process group.
                         */
                        pgrp = cp->p_pgrp;
+                       pgref(pgrp);
                } else {
                        pgrp = pgfind(pgid);
                        if (pgrp == NULL)
                                return (ESRCH);
                }
+
+               /*
+                * Must interlock all signals against fork
+                */
                lockmgr(&pgrp->pg_lock, LK_EXCLUSIVE);
                LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
                        if (p->p_pid <= 1 || 
@@ -710,6 +715,7 @@ dokillpg(int sig, int pgid, int all)
                                ksignal(p, sig);
                }
                lockmgr(&pgrp->pg_lock, LK_RELEASE);
+               pgrel(pgrp);
        }
        return (info.nfound ? 0 : ESRCH);
 }
@@ -754,7 +760,6 @@ kern_kill(int sig, pid_t pid, lwpid_t tid)
                        lwkt_reltoken(&proc_token);
                        return (ESRCH);
                }
-               PHOLD(p);
                lwkt_gettoken(&p->p_token);
                if (!CANSIGNAL(p, sig)) {
                        lwkt_reltoken(&p->p_token);
@@ -871,13 +876,18 @@ pgsignal(struct pgrp *pgrp, int sig, int checkctty)
 {
        struct proc *p;
 
+       /*
+        * Must interlock all signals against fork
+        */
        if (pgrp) {
+               pgref(pgrp);
                lockmgr(&pgrp->pg_lock, LK_EXCLUSIVE);
                LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
                        if (checkctty == 0 || p->p_flag & P_CONTROLT)
                                ksignal(p, sig);
                }
                lockmgr(&pgrp->pg_lock, LK_RELEASE);
+               pgrel(pgrp);
        }
 }
 
@@ -937,9 +947,10 @@ trapsignal(struct lwp *lp, int sig, u_long code)
 }
 
 /*
- * Find a suitable lwp to deliver the signal to.
+ * Find a suitable lwp to deliver the signal to.  Returns NULL if all
+ * lwps hold the signal blocked.
  *
- * Returns NULL if all lwps hold the signal blocked.
+ * Caller must hold p->p_token.
  */
 static struct lwp *
 find_lwp_for_signal(struct proc *p, int sig)
@@ -955,8 +966,10 @@ find_lwp_for_signal(struct proc *p, int sig)
         * soon anyways.
         */
        lp = lwkt_preempted_proc();
-       if (lp != NULL && lp->lwp_proc == p && !SIGISMEMBER(lp->lwp_sigmask, sig))
+       if (lp != NULL && lp->lwp_proc == p &&
+           !SIGISMEMBER(lp->lwp_sigmask, sig)) {
                return (lp);
+       }
 
        run = sleep = stop = NULL;
        FOREACH_LWP_IN_PROC(lp, p) {
@@ -1037,6 +1050,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig)
 
        KKASSERT(lp == NULL || lp->lwp_proc == p);
 
+       PHOLD(p);
        lwkt_gettoken(&p->p_token);
 
        prop = sigprop(sig);
@@ -1056,6 +1070,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig)
                 */
                if (lp && (lp->lwp_flag & LWP_WEXIT)) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        return;
                }
 
@@ -1066,6 +1081,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig)
                 */
                if (SIGISMEMBER(p->p_sigignore, sig)) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        return;
                }
                if (SIGISMEMBER(p->p_sigcatch, sig))
@@ -1090,6 +1106,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig)
                if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 &&
                    action == SIG_DFL) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        return;
                }
                SIG_CONTSIGMASK(p->p_siglist);
@@ -1252,6 +1269,7 @@ active_process:
 
 out:
        lwkt_reltoken(&p->p_token);
+       PRELE(p);
        crit_exit();
 }
 
@@ -2268,14 +2286,20 @@ pgsigio(struct sigio *sigio, int sig, int checkctty)
                        ksignal(sigio->sio_proc, sig);
        } else if (sigio->sio_pgid < 0) {
                struct proc *p;
+               struct pgrp *pg = sigio->sio_pgrp;
 
-               lockmgr(&sigio->sio_pgrp->pg_lock, LK_EXCLUSIVE);
-               LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) {
+               /*
+                * Must interlock all signals against fork
+                */
+               pgref(pg);
+               lockmgr(&pg->pg_lock, LK_EXCLUSIVE);
+               LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                        if (CANSIGIO(sigio->sio_ruid, sigio->sio_ucred, p) &&
                            (checkctty == 0 || (p->p_flag & P_CONTROLT)))
                                ksignal(p, sig);
                }
-               lockmgr(&sigio->sio_pgrp->pg_lock, LK_RELEASE);
+               lockmgr(&pg->pg_lock, LK_RELEASE);
+               pgrel(pg);
        }
 }
 
index f8d73ad..755a33d 100644 (file)
@@ -115,7 +115,7 @@ logclose(struct dev_close_args *ap)
        log_open = 0;
        callout_stop(&logsoftc.sc_callout);
        logsoftc.sc_state = 0;
-       funsetown(logsoftc.sc_sigio);
+       funsetown(&logsoftc.sc_sigio);
        return (0);
 }
 
index 6e425de..5f14a90 100644 (file)
@@ -1018,7 +1018,7 @@ pipe_close(struct file *fp)
        cpipe = (struct pipe *)fp->f_data;
        fp->f_ops = &badfileops;
        fp->f_data = NULL;
-       funsetown(cpipe->pipe_sigio);
+       funsetown(&cpipe->pipe_sigio);
        pipeclose(cpipe);
        return (0);
 }
index 9673903..bfb1c8e 100644 (file)
@@ -292,6 +292,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
        write = 0;
        if (req == PT_TRACE_ME) {
                p = curp;
+               PHOLD(p);
        } else {
                if ((p = pfind(pid)) == NULL) {
                        lwkt_reltoken(&proc_token);
@@ -299,6 +300,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                }
        }
        if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return (ESRCH);
        }
@@ -307,6 +309,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
        /* Can't trace a process that's currently exec'ing. */
        if ((p->p_flag & P_INEXEC) != 0) {
                lwkt_reltoken(&p->p_token);
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return EAGAIN;
        }
@@ -323,6 +326,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                /* Self */
                if (p->p_pid == curp->p_pid) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EINVAL;
                }
@@ -330,6 +334,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                /* Already traced */
                if (p->p_flag & P_TRACED) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EBUSY;
                }
@@ -338,6 +343,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                        for (pp = curp->p_pptr; pp != NULL; pp = pp->p_pptr)
                                if (pp == p) {
                                        lwkt_reltoken(&p->p_token);
+                                       PRELE(p);
                                        lwkt_reltoken(&proc_token);
                                        return (EINVAL);
                                }
@@ -347,6 +353,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                     (p->p_flag & P_SUGID)) {
                        if ((error = priv_check_cred(curp->p_ucred, PRIV_ROOT, 0)) != 0) {
                                lwkt_reltoken(&p->p_token);
+                               PRELE(p);
                                lwkt_reltoken(&proc_token);
                                return error;
                        }
@@ -355,6 +362,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                /* can't trace init when securelevel > 0 */
                if (securelevel > 0 && p->p_pid == 1) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EPERM;
                }
@@ -392,6 +400,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                /* not being traced... */
                if ((p->p_flag & P_TRACED) == 0) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EPERM;
                }
@@ -399,6 +408,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                /* not being traced by YOU */
                if (p->p_pptr != curp) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EBUSY;
                }
@@ -407,6 +417,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                if (p->p_stat != SSTOP ||
                    (p->p_flag & P_WAITED) == 0) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EBUSY;
                }
@@ -416,6 +427,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 
        default:
                lwkt_reltoken(&p->p_token);
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return EINVAL;
        }
@@ -441,6 +453,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                p->p_flag |= P_TRACED;
                p->p_oppid = p->p_pptr->p_pid;
                lwkt_reltoken(&p->p_token);
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return 0;
 
@@ -459,6 +472,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                /* Zero means do not send any signal */
                if (data < 0 || data > _SIG_MAXSIG) {
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EINVAL;
                }
@@ -469,6 +483,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                        if ((error = ptrace_single_step (lp))) {
                                LWPRELE(lp);
                                lwkt_reltoken(&p->p_token);
+                               PRELE(p);
                                lwkt_reltoken(&proc_token);
                                return error;
                        }
@@ -479,6 +494,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                            (u_long)(uintfptr_t)addr))) {
                                LWPRELE(lp);
                                lwkt_reltoken(&p->p_token);
+                               PRELE(p);
                                lwkt_reltoken(&proc_token);
                                return error;
                        }
@@ -515,6 +531,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                }
                crit_exit();
                lwkt_reltoken(&p->p_token);
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return 0;
 
@@ -559,6 +576,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                if (!write)
                        *res = tmp;
                lwkt_reltoken(&p->p_token);
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return (error);
 
@@ -589,12 +607,14 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                        break;
                default:
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return (EINVAL);
                }
                error = procfs_domem(curp, lp, NULL, &uio);
                piod->piod_len -= uio.uio_resid;
                lwkt_reltoken(&p->p_token);
+               PRELE(p);
                lwkt_reltoken(&proc_token);
                return (error);
 
@@ -614,6 +634,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 #if defined(PT_SETREGS) || defined(PT_GETREGS)
                if (!procfs_validregs(lp)) {    /* no P_SYSTEM procs please */
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EINVAL;
                } else {
@@ -628,6 +649,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                        uio.uio_td = curthread;
                        t = procfs_doregs(curp, lp, NULL, &uio);
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return t;
                }
@@ -645,6 +667,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
                if (!procfs_validfpregs(lp)) {  /* no P_SYSTEM procs please */
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EINVAL;
                } else {
@@ -659,6 +682,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                        uio.uio_td = curthread;
                        t = procfs_dofpregs(curp, lp, NULL, &uio);
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return t;
                }
@@ -676,6 +700,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
                if (!procfs_validdbregs(lp)) {  /* no P_SYSTEM procs please */
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return EINVAL;
                } else {
@@ -690,6 +715,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
                        uio.uio_td = curthread;
                        t = procfs_dodbregs(curp, lp, NULL, &uio);
                        lwkt_reltoken(&p->p_token);
+                       PRELE(p);
                        lwkt_reltoken(&proc_token);
                        return t;
                }
@@ -700,7 +726,9 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
        }
 
        lwkt_reltoken(&p->p_token);
+       PRELE(p);
        lwkt_reltoken(&proc_token);
+
        return 0;
 }
 
index fd86301..e616e1c 100644 (file)
@@ -256,7 +256,7 @@ ttyclose(struct tty *tp)
 {
        crit_enter();
        lwkt_gettoken(&tty_token);
-       funsetown(tp->t_sigio);
+       funsetown(&tp->t_sigio);
        if (constty == tp)
                constty = NULL;
 
@@ -288,9 +288,16 @@ void
 ttyclearsession(struct tty *tp)
 {
        struct session *sp;
+       struct pgrp *opgrp;
 
        lwkt_gettoken(&tty_token);
+       opgrp = tp->t_pgrp;
        tp->t_pgrp = NULL;
+       if (opgrp) {
+               pgrel(opgrp);
+               opgrp = NULL;
+       }
+
        if ((sp = tp->t_session) != NULL) {
                tp->t_session = NULL;
 #ifdef TTY_DO_FULL_CLOSE
@@ -845,6 +852,7 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag)
        struct thread *td = curthread;
        struct lwp *lp = td->td_lwp;
        struct proc *p = td->td_proc;
+       struct pgrp *opgrp;
        struct tty *otp;
        int error;
 
@@ -1206,12 +1214,18 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag)
                }
                ttyhold(tp);
                tp->t_session = p->p_session;
+               opgrp = tp->t_pgrp;
+               pgref(p->p_pgrp);
                tp->t_pgrp = p->p_pgrp;
                otp = p->p_session->s_ttyp;
                p->p_session->s_ttyp = tp;
+               p->p_flag |= P_CONTROLT;
                if (otp)
                        ttyunhold(otp);
-               p->p_flag |= P_CONTROLT;
+               if (opgrp) {
+                       pgrel(opgrp);
+                       opgrp = NULL;
+               }
                break;
        case TIOCSPGRP: {               /* set pgrp of tty */
                pid_t pgid = *(int *)data;
@@ -1228,12 +1242,18 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag)
                } else {
                        struct pgrp *pgrp = pgfind(pgid);
                        if (pgrp == NULL || pgrp->pg_session != p->p_session) {
+                               if (pgrp)
+                                       pgrel(pgrp);
                                lwkt_reltoken(&proc_token);
                                lwkt_reltoken(&tty_token);
                                return (EPERM);
                        }
-
+                       opgrp = tp->t_pgrp;
                        tp->t_pgrp = pgrp;
+                       if (opgrp) {
+                               pgrel(opgrp);
+                               opgrp = NULL;
+                       }
                }
                break;
        }
@@ -2553,7 +2573,7 @@ ttyinfo(struct tty *tp)
                ttyprintf(tp, "not a controlling terminal\n");
        } else if (tp->t_pgrp == NULL) {
                ttyprintf(tp, "no foreground process group\n");
-       } else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) {
+       } else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == NULL) {
                ttyprintf(tp, "empty foreground process group\n");
        } else {
                /*
@@ -2572,7 +2592,7 @@ ttyinfo(struct tty *tp)
 
                /* XXX lwp should compare lwps */
 
-               for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) {
+               for (pick = NULL; p != NULL; p = LIST_NEXT(p, p_pglist)) {
                        if (proc_compare(pick, p))
                                pick = p;
                }
index a3d137d..f523a21 100644 (file)
@@ -386,7 +386,7 @@ soclose(struct socket *so, int fflag)
 {
        int error = 0;
 
-       funsetown(so->so_sigio);
+       funsetown(&so->so_sigio);
        if (so->so_pcb == NULL)
                goto discard;
        if (so->so_state & SS_ISCONNECTED) {
index 7b76328..4950a4c 100644 (file)
@@ -1372,7 +1372,8 @@ sf_buf_mfree(void *arg)
        vm_page_t m;
 
        m = sf_buf_page(sf);
-       if (sf_buf_free(sf) == 0) {
+       if (sf_buf_free(sf)) {
+               /* sf invalid now */
                vm_page_unwire(m, 0);
                if (m->wire_count == 0 && m->object == NULL)
                        vm_page_try_to_free(m);
index 0924d57..2ff5de6 100644 (file)
@@ -369,7 +369,7 @@ bpfclose(struct dev_close_args *ap)
        cdev_t dev = ap->a_head.a_dev;
        struct bpf_d *d = dev->si_drv1;
 
-       funsetown(d->bd_sigio);
+       funsetown(&d->bd_sigio);
        crit_enter();
        if (d->bd_state == BPF_WAITING)
                callout_stop(&d->bd_callout);
index d2d0949..7426ca8 100644 (file)
@@ -424,12 +424,12 @@ tapclose(struct dev_close_args *ap)
                rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
        }
 
-       funsetown(tp->tap_sigio);
+       funsetown(&tp->tap_sigio);
        tp->tap_sigio = NULL;
        KNOTE(&tp->tap_rkq.ki_note, 0);
 
        tp->tap_flags &= ~TAP_OPEN;
-       funsetown(tp->tap_sigtd);
+       funsetown(&tp->tap_sigtd);
        tp->tap_sigtd = NULL;
 
        taprefcnt --;
index 5f4e259..54cb34f 100644 (file)
@@ -216,7 +216,7 @@ tunclose(struct dev_close_args *ap)
        ifp->if_flags &= ~IFF_RUNNING;
        if_purgeaddrs_nolink(ifp);
 
-       funsetown(tp->tun_sigio);
+       funsetown(&tp->tun_sigio);
        KNOTE(&tp->tun_rkq.ki_note, 0);
 
        TUNDEBUG(ifp, "closed\n");
index b7b4d43..38213a9 100644 (file)
@@ -292,7 +292,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
                        struct proc *p;
                        struct pcb *pcb;
 
-                       p = pfind(pid);
+                       p = pfindn(pid);
                        if (p == NULL) {
                                db_printf("pid %d not found\n", pid);
                                return;
index dd177af..4e77991 100644 (file)
@@ -133,8 +133,7 @@ struct      sigio {
                struct  pgrp *siu_pgrp; /* process group to receive ... */
        } sio_u;
        SLIST_ENTRY(sigio) sio_pgsigio; /* sigio's for process or group */
-       struct  sigio **sio_myref;      /* location of the pointer that holds
-                                        * the reference to this structure */
+       struct  sigio **sio_myref;      /* location of the pointer that holds */
        struct  ucred *sio_ucred;       /* current credentials */
        uid_t   sio_ruid;               /* real user id */
        pid_t   sio_pgid;               /* pgid for signals */
@@ -178,7 +177,7 @@ int fdissequential (struct file *);
 void   fdsequential (struct file *, int);
 pid_t  fgetown (struct sigio **);
 int    fsetown (pid_t, struct sigio **);
-void   funsetown (struct sigio *);
+void   funsetown (struct sigio **);
 void   funsetownlst (struct sigiolst *);
 void   setugidsafety (struct proc *p);
 void   allfiles_scan_exclusive(int (*callback)(struct file *, void *), void *data);
index dc24a4e..d688693 100644 (file)
@@ -106,7 +106,9 @@ struct      pgrp {
        struct  sigiolst pg_sigiolst;   /* List of sigio sources. */
        pid_t   pg_id;                  /* Pgrp id. */
        int     pg_jobc;        /* # procs qualifying pgrp for job control */
-       struct lock pg_lock;            /* Lock during fork */
+       u_int   pg_refs;
+       struct lwkt_token pg_token;
+       struct lock pg_lock;
 };
 
 #define        PS_NOCLDWAIT    0x0001  /* No zombies if child dies */
@@ -437,7 +439,9 @@ extern void stopevent(struct proc*, unsigned int, unsigned int);
        } while (0)
 
 /*
- * Hold process in memory, don't destruct , normally for ptrace/procfs work
+ * Hold process in memory, don't destruct, used by ktrace, procfs, sigio,
+ * and signaling code (e.g. ksignal()).
+ *
  * MPSAFE
  */
 #define PHOLD(p)       atomic_add_int(&(p)->p_lock, 1)
@@ -489,9 +493,12 @@ extern     u_long ps_arg_cache_limit;
 extern int ps_argsopen;
 extern int ps_showallprocs;
 
-struct proc *pfind (pid_t);    /* Find process by id. */
-struct pgrp *pgfind (pid_t);   /* Find process group by id. */
-struct proc *zpfind (pid_t);   /* Find zombie process by id. */
+struct proc *pfind (pid_t);    /* Find process by id w/ref */
+struct proc *pfindn (pid_t);   /* Find process by id wo/ref */
+struct pgrp *pgfind (pid_t);   /* Find process group by id w/ref */
+struct proc *zpfind (pid_t);   /* Find zombie process by id w/ref */
+void pgref (struct pgrp *);    /* Ref pgrp preventing disposal */
+void pgrel (struct pgrp *);    /* Deref pgrp & dispose on 1->0 trans */
 
 struct globaldata;
 struct lwp_params;
index 1d4d804..98ea68c 100644 (file)
@@ -122,8 +122,6 @@ struct reg;
 struct fpreg;
 struct dbreg;
 
-#define PFIND(pid) ((pid) ? pfind(pid) : &proc0)
-
 void procfs_exit (struct thread *);
 int procfs_freevp (struct vnode *);
 int procfs_allocvp (struct mount *, struct vnode **, long, pfstype);
index 3fb9295..c8f9216 100644 (file)
@@ -218,8 +218,10 @@ procfs_control(struct proc *curp, struct lwp *lp, int op)
                        struct proc *pp;
 
                        pp = pfind(p->p_oppid);
-                       if (pp)
+                       if (pp) {
                                proc_reparent(p, pp);
+                               PRELE(pp);
+                       }
                }
 
                p->p_oppid = 0;
index ce18058..44847a0 100644 (file)
@@ -274,13 +274,14 @@ procfs_rw(struct vop_read_args *ap)
 
        lwkt_gettoken(&proc_token);
 
-       p = PFIND(pfs->pfs_pid);
+       p = pfind(pfs->pfs_pid);
        if (p == NULL) {
                lwkt_reltoken(&proc_token);
                return (EINVAL);
        }
        if (p->p_pid == 1 && securelevel > 0 && uio->uio_rw == UIO_WRITE) {
                lwkt_reltoken(&proc_token);
+               PRELE(p);
                return (EACCES);
        }
        /* XXX lwp */
@@ -350,6 +351,7 @@ procfs_rw(struct vop_read_args *ap)
        pfs->pfs_lockowner = 0;
        lwkt_reltoken(&proc_token);
        wakeup(&pfs->pfs_lockowner);
+       PRELE(p);
 
        return rtval;
 }
index cb1b968..9ca253e 100644 (file)
@@ -172,26 +172,35 @@ procfs_open(struct vop_open_args *ap)
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        struct proc *p1, *p2;
+       int error;
 
-       p2 = PFIND(pfs->pfs_pid);
+       p2 = pfind(pfs->pfs_pid);
        if (p2 == NULL)
                return (ENOENT);
-       if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred))
-               return (ENOENT);
+       if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred)) {
+               error = ENOENT;
+               goto done;
+       }
 
        switch (pfs->pfs_type) {
        case Pmem:
                if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
-                   ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
-                       return (EBUSY);
+                   ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
+                       error = EBUSY;
+                       goto done;
+               }
 
                p1 = curproc;
                KKASSERT(p1);
                /* Can't trace a process that's currently exec'ing. */ 
-               if ((p2->p_flag & P_INEXEC) != 0)
-                       return EAGAIN;
-               if (!CHECKIO(p1, p2) || p_trespass(ap->a_cred, p2->p_ucred))
-                       return (EPERM);
+               if ((p2->p_flag & P_INEXEC) != 0) {
+                       error = EAGAIN;
+                       goto done;
+               }
+               if (!CHECKIO(p1, p2) || p_trespass(ap->a_cred, p2->p_ucred)) {
+                       error = EPERM;
+                       goto done;
+               }
 
                if (ap->a_mode & FWRITE)
                        pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
@@ -201,8 +210,10 @@ procfs_open(struct vop_open_args *ap)
        default:
                break;
        }
-
-       return (vop_stdopen(ap));
+       error = vop_stdopen(ap);
+done:
+       PRELE(p2);
+       return error;
 }
 
 /*
@@ -235,6 +246,7 @@ procfs_close(struct vop_close_args *ap)
                 * told to stop on an event, but then the requesting process
                 * has gone away or forgotten about it.
                 */
+               p = NULL;
                if ((ap->a_vp->v_opencount < 2)
                    && (p = pfind(pfs->pfs_pid))
                    && !(p->p_pfsflags & PF_LINGER)) {
@@ -244,6 +256,8 @@ procfs_close(struct vop_close_args *ap)
                        spin_unlock(&p->p_spin);
                        wakeup(&p->p_step);
                }
+               if (p)
+                       PRELE(p);
                break;
        default:
                break;
@@ -271,14 +285,20 @@ procfs_ioctl(struct vop_ioctl_args *ap)
        if (procp == NULL)
                return ENOTTY;
        p = curproc;
-       if (p == NULL)
-               return EINVAL;
+       if (p == NULL) {
+               error = EINVAL;
+               goto done;
+       }
 
        /* Can't trace a process that's currently exec'ing. */ 
-       if ((procp->p_flag & P_INEXEC) != 0)
-               return EAGAIN;
-       if (!CHECKIO(p, procp) || p_trespass(ap->a_cred, procp->p_ucred))
-               return EPERM;
+       if ((procp->p_flag & P_INEXEC) != 0) {
+               error = EAGAIN;
+               goto done;
+       }
+       if (!CHECKIO(p, procp) || p_trespass(ap->a_cred, procp->p_ucred)) {
+               error = EPERM;
+               goto done;
+       }
 
        switch (ap->a_command) {
        case PIOCBIS:
@@ -295,7 +315,7 @@ procfs_ioctl(struct vop_ioctl_args *ap)
 #define NFLAGS (PF_ISUGID)
          flags = (unsigned char)*(unsigned int*)ap->a_data;
          if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)))
-           return error;
+           goto done;
          procp->p_pfsflags = flags;
          break;
        case PIOCGFL:
@@ -334,7 +354,7 @@ procfs_ioctl(struct vop_ioctl_args *ap)
            spin_unlock(&procp->p_spin);
            error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED, "piocwait", 0);
            if (error)
-             return error;
+             goto done;
            spin_lock(&procp->p_spin);
          }
          spin_unlock(&procp->p_spin);
@@ -350,19 +370,27 @@ procfs_ioctl(struct vop_ioctl_args *ap)
           *       the MP lock.  However, the caller is presumably interlocked
           *       by having waited.
           */
-         if (procp->p_step == 0)
-           return EINVAL;      /* Can only start a stopped process */
+         if (procp->p_step == 0) {
+           error = EINVAL;     /* Can only start a stopped process */
+           goto done;
+         }
          if ((signo = *(int*)ap->a_data) != 0) {
-           if (signo >= NSIG || signo <= 0)
-             return EINVAL;
+           if (signo >= NSIG || signo <= 0) {
+             error = EINVAL;
+             goto done;
+           }
            ksignal(procp, signo);
          }
          procp->p_step = 0;
          wakeup(&procp->p_step);
          break;
        default:
-         return (ENOTTY);
+         error = ENOTTY;
+         goto done;
        }
+       error = 0;
+done:
+       PRELE(procp);
        return 0;
 }
 
@@ -481,13 +509,15 @@ procfs_getattr(struct vop_getattr_args *ap)
        switch (pfs->pfs_type) {
        case Proot:
        case Pcurproc:
-               procp = 0;
+               procp = NULL;
                break;
 
        default:
-               procp = PFIND(pfs->pfs_pid);
-               if (procp == NULL || procp->p_ucred == NULL)
-                       return (ENOENT);
+               procp = pfind(pfs->pfs_pid);
+               if (procp == NULL || procp->p_ucred == NULL) {
+                       error = ENOENT;
+                       goto done;
+               }
        }
 
        error = 0;
@@ -627,7 +657,9 @@ procfs_getattr(struct vop_getattr_args *ap)
        default:
                panic("procfs_getattr");
        }
-
+done:
+       if (procp)
+               PRELE(procp);
        return (error);
 }
 
@@ -699,6 +731,7 @@ procfs_lookup(struct vop_old_lookup_args *ap)
        if (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)
                return (EROFS);
 
+       p = NULL;
        error = 0;
        if (cnp->cn_namelen == 1 && *pname == '.') {
                *vpp = dvp;
@@ -721,7 +754,7 @@ procfs_lookup(struct vop_old_lookup_args *ap)
                if (pid == NO_PID)
                        break;
 
-               p = PFIND(pid);
+               p = pfind(pid);
                if (p == NULL)
                        break;
 
@@ -741,7 +774,7 @@ procfs_lookup(struct vop_old_lookup_args *ap)
                        goto out;
                }
 
-               p = PFIND(pfs->pfs_pid);
+               p = pfind(pfs->pfs_pid);
                if (p == NULL)
                        break;
                /* XXX lwp */
@@ -787,6 +820,8 @@ out:
                        vn_unlock(dvp);
                }
        }
+       if (p)
+               PRELE(p);
        return (error);
 }
 
@@ -857,18 +892,22 @@ procfs_readdir_proc(struct vop_readdir_args *ap)
        struct uio *uio = ap->a_uio;
 
        pfs = VTOPFS(ap->a_vp);
-       p = PFIND(pfs->pfs_pid);
+       p = pfind(pfs->pfs_pid);
        if (p == NULL)
                return(0);
-       if (!PRISON_CHECK(ap->a_cred, p->p_ucred))
-               return(0);
-       /* XXX lwp */
+       if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) {
+               error = 0;
+               goto done;
+       }
+       /* XXX lwp, not MPSAFE */
        lp = FIRST_LWP_IN_PROC(p);
 
        error = 0;
        i = (int)uio->uio_offset;
-       if (i < 0)
-               return (EINVAL);
+       if (i < 0) {
+               error = EINVAL;
+               goto done;
+       }
 
        for (pt = &proc_targets[i];
             !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
@@ -883,8 +922,10 @@ procfs_readdir_proc(struct vop_readdir_args *ap)
        }
 
        uio->uio_offset = (off_t)i;
-
-       return(0);
+       error = 0;
+done:
+       PRELE(p);
+       return error;
 }
 
 struct procfs_readdir_root_info {
@@ -1032,19 +1073,26 @@ procfs_readlink(struct vop_readlink_args *ap)
         * from under us...
         */
        case Pfile:
-               procp = PFIND(pfs->pfs_pid);
+               procp = pfind(pfs->pfs_pid);
                if (procp == NULL || procp->p_ucred == NULL) {
                        kprintf("procfs_readlink: pid %d disappeared\n",
                            pfs->pfs_pid);
+                       if (procp)
+                               PRELE(procp);
                        return (uiomove("unknown", sizeof("unknown") - 1,
                            ap->a_uio));
                }
                error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
-               if (error != 0)
+               if (error != 0) {
+                       if (procp)
+                               PRELE(procp);
                        return (uiomove("unknown", sizeof("unknown") - 1,
                            ap->a_uio));
+               }
                error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
                kfree(freepath, M_TEMP);
+               if (procp)
+                       PRELE(procp);
                return (error);
        default:
                return (EINVAL);