From a09da298590e8c11ebafa37f79e0046814665237 Mon Sep 17 00:00:00 2001 From: tanimura Date: Sat, 23 Feb 2002 11:12:57 +0000 Subject: Lock struct pgrp, session and sigio. New locks are: - pgrpsess_lock which locks the whole pgrps and sessions, - pg_mtx which protects the pgrp members, and - s_mtx which protects the session members. Please refer to sys/proc.h for the coverage of these locks. Changes on the pgrp/session interface: - pgfind() needs the pgrpsess_lock held. - The caller of enterpgrp() is responsible to allocate a new pgrp and session. - Call enterthispgrp() in order to enter an existing pgrp. - pgsignal() requires a pgrp lock held. Reviewed by: jhb, alfred Tested on: cvsup.jp.FreeBSD.org (which is a quad-CPU machine running -current) --- sys/kern/init_main.c | 2 + sys/kern/kern_acct.c | 4 + sys/kern/kern_descrip.c | 109 +++++++++++++++--- sys/kern/kern_exit.c | 64 ++++++++--- sys/kern/kern_fork.c | 8 +- sys/kern/kern_ktrace.c | 8 ++ sys/kern/kern_proc.c | 290 ++++++++++++++++++++++++++++++++++------------- sys/kern/kern_prot.c | 162 +++++++++++++++++++------- sys/kern/kern_resource.c | 34 +++++- sys/kern/kern_sig.c | 44 ++++--- sys/kern/subr_prf.c | 60 +++++++--- sys/kern/subr_witness.c | 4 + sys/kern/sys_process.c | 6 +- sys/kern/tty.c | 195 ++++++++++++++++++++++--------- sys/kern/tty_pty.c | 19 +++- sys/kern/tty_tty.c | 56 +++++++-- sys/kern/vfs_aio.c | 10 +- sys/kern/vfs_vnops.c | 21 +++- 18 files changed, 833 insertions(+), 263 deletions(-) (limited to 'sys/kern') diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 6b698e4..6de34ef 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -305,12 +305,14 @@ proc0_init(void *dummy __unused) */ LIST_INSERT_HEAD(&allproc, p, p_list); LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); + mtx_init(&pgrp0.pg_mtx, "process group", MTX_DEF); p->p_pgrp = &pgrp0; LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); LIST_INIT(&pgrp0.pg_members); LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); pgrp0.pg_session = &session0; + mtx_init(&session0.s_mtx, "session", MTX_DEF); session0.s_count = 1; session0.s_leader = p; diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index cd191d5..e859057 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -233,10 +233,14 @@ acct_process(td) acct.ac_gid = p->p_ucred->cr_rgid; /* (7) The terminal from which the process was started */ + PROC_LOCK(p); + SESS_LOCK(p->p_session); if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) acct.ac_tty = dev2udev(p->p_pgrp->pg_session->s_ttyp->t_dev); else acct.ac_tty = NOUDEV; + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); /* (8) The boolean flags that tell how the process terminated, etc. */ acct.ac_flag = p->p_acflag; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index ea7fa2d..8e4726e 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -535,15 +535,22 @@ funsetown(sigio) if (sigio == NULL) return; + s = splhigh(); *(sigio->sio_myref) = NULL; splx(s); - if (sigio->sio_pgid < 0) { + if ((sigio)->sio_pgid < 0) { + struct pgrp *pg = (sigio)->sio_pgrp; + PGRP_LOCK(pg); SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio, sigio, sio_pgsigio); - } else /* if ((*sigiop)->sio_pgid > 0) */ { + PGRP_UNLOCK(pg); + } else { + struct proc *p = (sigio)->sio_proc; + PROC_LOCK(p); SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio, sigio, sio_pgsigio); + PROC_UNLOCK(p); } crfree(sigio->sio_ucred); FREE(sigio, M_SIGIO); @@ -554,10 +561,52 @@ void funsetownlst(sigiolst) struct sigiolst *sigiolst; { + int s; struct sigio *sigio; + struct proc *p; + struct pgrp *pg; + + sigio = SLIST_FIRST(sigiolst); + if (sigio == NULL) + return; + + p = NULL; + pg = NULL; + + /* + * Every entry of the list should belong + * to a single proc or pgrp. + */ + if (sigio->sio_pgid < 0) { + pg = sigio->sio_pgrp; + PGRP_LOCK_ASSERT(pg, MA_OWNED); + } else /* if (sigio->sio_pgid > 0) */ { + p = sigio->sio_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + } - while ((sigio = SLIST_FIRST(sigiolst)) != NULL) - funsetown(sigio); + while ((sigio = SLIST_FIRST(sigiolst)) != NULL) { + s = splhigh(); + *(sigio->sio_myref) = NULL; + splx(s); + if (pg != NULL) { + KASSERT(sigio->sio_pgid < 0, ("Proc sigio in pgrp sigio list")); + KASSERT(sigio->sio_pgrp == pg, ("Bogus pgrp in sigio list")); + SLIST_REMOVE(&pg->pg_sigiolst, sigio, sigio, sio_pgsigio); + PGRP_UNLOCK(pg); + crfree(sigio->sio_ucred); + FREE(sigio, M_SIGIO); + PGRP_LOCK(pg); + } else /* if (p != NULL) */ { + KASSERT(sigio->sio_pgid > 0, ("Pgrp sigio in proc sigio list")); + KASSERT(sigio->sio_proc == p, ("Bogus proc in sigio list")); + SLIST_REMOVE(&p->p_sigiolst, sigio, sigio, sio_pgsigio); + PROC_UNLOCK(p); + crfree(sigio->sio_ucred); + FREE(sigio, M_SIGIO); + PROC_LOCK(p); + } + } } /* @@ -574,16 +623,28 @@ fsetown(pgid, sigiop) struct proc *proc; struct pgrp *pgrp; struct sigio *sigio; - int s; + int s, ret; if (pgid == 0) { funsetown(*sigiop); return (0); } + + ret = 0; + + /* Allocate and fill in the new sigio out of locks. */ + MALLOC(sigio, struct sigio *, sizeof(struct sigio), M_SIGIO, M_WAITOK); + sigio->sio_pgid = pgid; + sigio->sio_ucred = crhold(curthread->td_proc->p_ucred); + sigio->sio_myref = sigiop; + + PGRPSESS_SLOCK(); if (pgid > 0) { proc = pfind(pgid); - if (proc == NULL) - return (ESRCH); + if (proc == NULL) { + ret = ESRCH; + goto fail; + } /* * Policy - Don't allow a process to FSETOWN a process @@ -593,17 +654,20 @@ fsetown(pgid, sigiop) * restrict FSETOWN to the current process or process * group for maximum safety. */ + PROC_UNLOCK(proc); if (proc->p_session != curthread->td_proc->p_session) { - PROC_UNLOCK(proc); - return (EPERM); + ret = EPERM; + goto fail; } - PROC_UNLOCK(proc); pgrp = NULL; } else /* if (pgid < 0) */ { pgrp = pgfind(-pgid); - if (pgrp == NULL) - return (ESRCH); + if (pgrp == NULL) { + ret = ESRCH; + goto fail; + } + PGRP_UNLOCK(pgrp); /* * Policy - Don't allow a process to FSETOWN a process @@ -613,27 +677,36 @@ fsetown(pgid, sigiop) * restrict FSETOWN to the current process or process * group for maximum safety. */ - if (pgrp->pg_session != curthread->td_proc->p_session) - return (EPERM); + if (pgrp->pg_session != curthread->td_proc->p_session) { + ret = EPERM; + goto fail; + } proc = NULL; } funsetown(*sigiop); - MALLOC(sigio, struct sigio *, sizeof(struct sigio), M_SIGIO, M_WAITOK); if (pgid > 0) { + PROC_LOCK(proc); SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio); sigio->sio_proc = proc; + PROC_UNLOCK(proc); } else { + PGRP_LOCK(pgrp); SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio); sigio->sio_pgrp = pgrp; + PGRP_UNLOCK(pgrp); } - sigio->sio_pgid = pgid; - sigio->sio_ucred = crhold(curthread->td_proc->p_ucred); - sigio->sio_myref = sigiop; + PGRPSESS_SUNLOCK(); s = splhigh(); *sigiop = sigio; splx(s); return (0); + +fail: + PGRPSESS_SUNLOCK(); + crfree(sigio->sio_ucred); + FREE(sigio, M_SIGIO); + return (ret); } /* diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index c8503ca..37d2ab1 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -125,6 +125,8 @@ exit1(td, rv) register struct vmspace *vm; struct vnode *vtmp; struct exitlist *ep; + struct vnode *ttyvp; + struct tty *tp; GIANT_REQUIRED; @@ -186,7 +188,9 @@ exit1(td, rv) * Reset any sigio structures pointing to us as a result of * F_SETOWN with our pid. */ + PROC_LOCK(p); funsetownlst(&p->p_sigiolst); + PROC_UNLOCK(p); /* * Close open files and release open-file table. @@ -227,11 +231,11 @@ exit1(td, rv) vm->vm_freer = p; } - PROC_LOCK(p); + PGRPSESS_XLOCK(); if (SESS_LEADER(p)) { - register struct session *sp = p->p_session; + register struct session *sp; - PROC_UNLOCK(p); + sp = p->p_session; if (sp->s_ttyvp) { /* * Controlling process. @@ -240,29 +244,48 @@ exit1(td, rv) * and revoke access to controlling terminal. */ if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) { - if (sp->s_ttyp->t_pgrp) + tp = sp->s_ttyp; + if (sp->s_ttyp->t_pgrp) { + PGRP_LOCK(sp->s_ttyp->t_pgrp); pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); - (void) ttywait(sp->s_ttyp); + PGRP_UNLOCK(sp->s_ttyp->t_pgrp); + } + /* XXX tp should be locked. */ + (void) ttywait(tp); /* * The tty could have been revoked * if we blocked. */ - if (sp->s_ttyvp) - VOP_REVOKE(sp->s_ttyvp, REVOKEALL); + if (sp->s_ttyvp) { + ttyvp = sp->s_ttyvp; + SESS_LOCK(p->p_session); + sp->s_ttyvp = NULL; + SESS_UNLOCK(p->p_session); + PGRPSESS_XUNLOCK(); + VOP_REVOKE(ttyvp, REVOKEALL); + PGRPSESS_XLOCK(); + vrele(ttyvp); + } + } + if (sp->s_ttyvp) { + ttyvp = sp->s_ttyvp; + SESS_LOCK(p->p_session); + sp->s_ttyvp = NULL; + SESS_UNLOCK(p->p_session); + vrele(ttyvp); } - if (sp->s_ttyvp) - vrele(sp->s_ttyvp); - sp->s_ttyvp = NULL; /* * s_ttyp is not zero'd; we use this to indicate * that the session once had a controlling terminal. * (for logging and informational purposes) */ } + SESS_LOCK(p->p_session); sp->s_leader = NULL; - } else - PROC_UNLOCK(p); + SESS_UNLOCK(p->p_session); + } fixjobc(p, p->p_pgrp, 0); + PGRPSESS_XUNLOCK(); (void)acct_process(td); #ifdef KTRACE /* @@ -309,7 +332,7 @@ exit1(td, rv) q->p_flag &= ~P_TRACED; psignal(q, SIGKILL); } - PROC_UNLOCK(q); + PROC_UNLOCK(q); } /* @@ -338,6 +361,7 @@ exit1(td, rv) * notify interested parties of our demise. */ PROC_LOCK(p); + PROC_LOCK(p->p_pptr); KNOTE(&p->p_klist, NOTE_EXIT); /* @@ -347,7 +371,9 @@ exit1(td, rv) */ if (p->p_pptr->p_procsig->ps_flag & PS_NOCLDWAIT) { struct proc *pp = p->p_pptr; + PROC_UNLOCK(pp); proc_reparent(p, initproc); + PROC_LOCK(p->p_pptr); /* * If this was the last child of our parent, notify * parent, so in case he was wait(2)ing, he will @@ -357,7 +383,6 @@ exit1(td, rv) wakeup((caddr_t)pp); } - PROC_LOCK(p->p_pptr); if (p->p_sigparent && p->p_pptr != initproc) psignal(p->p_pptr, p->p_sigparent); else @@ -480,8 +505,11 @@ wait1(td, uap, compat) mtx_lock(&Giant); q = td->td_proc; - if (uap->pid == 0) + if (uap->pid == 0) { + PROC_LOCK(q); uap->pid = -q->p_pgid; + PROC_UNLOCK(q); + } if (uap->options &~ (WUNTRACED|WNOHANG|WLINUXCLONE)) { error = EINVAL; goto done2; @@ -490,9 +518,12 @@ loop: nfound = 0; sx_slock(&proctree_lock); LIST_FOREACH(p, &q->p_children, p_sibling) { + PROC_LOCK(p); if (uap->pid != WAIT_ANY && - p->p_pid != uap->pid && p->p_pgid != -uap->pid) + p->p_pid != uap->pid && p->p_pgid != -uap->pid) { + PROC_UNLOCK(p); continue; + } /* * This special case handles a kthread spawned by linux_clone @@ -502,7 +533,6 @@ loop: * p_sigparent is not SIGCHLD, and the WLINUXCLONE option * signifies we want to wait for threads and not processes. */ - PROC_LOCK(p); if ((p->p_sigparent != SIGCHLD) ^ ((uap->options & WLINUXCLONE) != 0)) { PROC_UNLOCK(p); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 8fe1006..69071a1 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -382,12 +382,15 @@ retry: p2 = LIST_FIRST(&allproc); again: for (; p2 != NULL; p2 = LIST_NEXT(p2, p_list)) { + PROC_LOCK(p2); while (p2->p_pid == trypid || p2->p_pgrp->pg_id == trypid || p2->p_session->s_sid == trypid) { trypid++; - if (trypid >= pidchecked) + if (trypid >= pidchecked) { + PROC_UNLOCK(p2); goto retry; + } } if (p2->p_pid > trypid && pidchecked > p2->p_pid) pidchecked = p2->p_pid; @@ -397,6 +400,7 @@ again: if (p2->p_session->s_sid > trypid && pidchecked > p2->p_session->s_sid) pidchecked = p2->p_session->s_sid; + PROC_UNLOCK(p2); } if (!doingzomb) { doingzomb = 1; @@ -559,8 +563,10 @@ again: * been preserved. */ p2->p_flag |= p1->p_flag & (P_SUGID | P_ALTSTACK); + SESS_LOCK(p1->p_session); if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) p2->p_flag |= P_CONTROLT; + SESS_UNLOCK(p1->p_session); if (flags & RFPPWAIT) p2->p_flag |= P_PPWAIT; diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index db44873..6fc46d6 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -350,16 +350,24 @@ ktrace(td, uap) /* * by process group */ + PGRPSESS_SLOCK(); pg = pgfind(-uap->pid); if (pg == NULL) { + PGRPSESS_SUNLOCK(); error = ESRCH; goto done; } + /* + * ktrops() may call vrele(). Lock pg_members + * by the pgrpsess_lock rather than pg_mtx. + */ + PGRP_UNLOCK(pg); LIST_FOREACH(p, &pg->pg_members, p_pglist) if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); + PGRPSESS_SUNLOCK(); } else { /* * by pid diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index b11c23b..27222fa 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -55,14 +55,18 @@ #include #include -static MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); +MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); MALLOC_DEFINE(M_SESSION, "session", "session header"); static MALLOC_DEFINE(M_PROC, "proc", "Proc structures"); MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures"); +static struct proc *dopfind __P((register pid_t)); + +static void doenterpgrp __P((struct proc *, struct pgrp *)); + static void pgdelete __P((struct pgrp *)); -static void orphanpg __P((struct pgrp *pg)); +static void orphanpg __P((struct pgrp *pg)); /* * Other process lists @@ -75,6 +79,7 @@ struct proclist allproc; struct proclist zombproc; struct sx allproc_lock; struct sx proctree_lock; +struct sx pgrpsess_lock; vm_zone_t proc_zone; vm_zone_t ithread_zone; @@ -88,6 +93,7 @@ procinit() sx_init(&allproc_lock, "allproc"); sx_init(&proctree_lock, "proctree"); + sx_init(&pgrpsess_lock, "pgrpsess"); LIST_INIT(&allproc); LIST_INIT(&zombproc); pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); @@ -265,17 +271,30 @@ pfind(pid) register struct proc *p; sx_slock(&allproc_lock); + p = dopfind(pid); + sx_sunlock(&allproc_lock); + return (p); +} + +static struct proc * +dopfind(pid) + register pid_t pid; +{ + register struct proc *p; + + sx_assert(&allproc_lock, SX_LOCKED); + LIST_FOREACH(p, PIDHASH(pid), p_hash) if (p->p_pid == pid) { PROC_LOCK(p); break; } - sx_sunlock(&allproc_lock); return (p); } /* - * Locate a process group by number + * Locate a process group by number. + * The caller must hold pgrpsess_lock. */ struct pgrp * pgfind(pgid) @@ -283,77 +302,132 @@ pgfind(pgid) { register struct pgrp *pgrp; - LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) - if (pgrp->pg_id == pgid) + PGRPSESS_LOCK_ASSERT(SX_LOCKED); + + LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) { + if (pgrp->pg_id == pgid) { + PGRP_LOCK(pgrp); return (pgrp); + } + } return (NULL); } /* - * Move p to a new or existing process group (and session) + * Create a new process group. + * pgid must be equal to the pid of p. + * Begin a new session if required. */ int -enterpgrp(p, pgid, mksess) +enterpgrp(p, pgid, pgrp, sess) register struct proc *p; pid_t pgid; - int mksess; + struct pgrp *pgrp; + struct session *sess; { - register struct pgrp *pgrp = pgfind(pgid); - struct pgrp *savegrp; + struct pgrp *pgrp2; - KASSERT(pgrp == NULL || !mksess, - ("enterpgrp: setsid into non-empty pgrp")); + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + + KASSERT(pgrp != NULL, ("enterpgrp: pgrp == NULL")); + KASSERT(p->p_pid == pgid, + ("enterpgrp: new pgrp and pid != pgid")); + + pgrp2 = pgfind(pgid); + + KASSERT(pgrp2 == NULL, + ("enterpgrp: pgrp with pgid exists")); KASSERT(!SESS_LEADER(p), ("enterpgrp: session leader attempted setpgrp")); - if (pgrp == NULL) { - pid_t savepid = p->p_pid; - struct proc *np; + mtx_init(&pgrp->pg_mtx, "process group", MTX_DEF); + + if (sess != NULL) { /* - * new process group + * new session */ - KASSERT(p->p_pid == pgid, - ("enterpgrp: new pgrp and pid != pgid")); - if ((np = pfind(savepid)) == NULL || np != p) { - if (np != NULL) - PROC_UNLOCK(np); - return (ESRCH); - } - PROC_UNLOCK(np); - MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, - M_WAITOK); - if (mksess) { - register struct session *sess; - - /* - * new session - */ - MALLOC(sess, struct session *, sizeof(struct session), - M_SESSION, M_WAITOK); - sess->s_leader = p; - sess->s_sid = p->p_pid; - sess->s_count = 1; - sess->s_ttyvp = NULL; - sess->s_ttyp = NULL; - bcopy(p->p_session->s_login, sess->s_login, + mtx_init(&sess->s_mtx, "session", MTX_DEF); + PROC_LOCK(p); + p->p_flag &= ~P_CONTROLT; + PROC_UNLOCK(p); + PGRP_LOCK(pgrp); + sess->s_leader = p; + sess->s_sid = p->p_pid; + sess->s_count = 1; + sess->s_ttyvp = NULL; + sess->s_ttyp = NULL; + bcopy(p->p_session->s_login, sess->s_login, sizeof(sess->s_login)); - PROC_LOCK(p); - p->p_flag &= ~P_CONTROLT; - PROC_UNLOCK(p); - pgrp->pg_session = sess; - KASSERT(p == curproc, - ("enterpgrp: mksession and p != curproc")); - } else { - pgrp->pg_session = p->p_session; - pgrp->pg_session->s_count++; - } - pgrp->pg_id = pgid; - LIST_INIT(&pgrp->pg_members); - LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); - pgrp->pg_jobc = 0; - SLIST_INIT(&pgrp->pg_sigiolst); - } else if (pgrp == p->p_pgrp) - return (0); + pgrp->pg_session = sess; + KASSERT(p == curproc, + ("enterpgrp: mksession and p != curproc")); + } else { + pgrp->pg_session = p->p_session; + SESS_LOCK(pgrp->pg_session); + pgrp->pg_session->s_count++; + SESS_UNLOCK(pgrp->pg_session); + PGRP_LOCK(pgrp); + } + pgrp->pg_id = pgid; + LIST_INIT(&pgrp->pg_members); + + /* + * As we have an exclusive lock of pgrpsess_lock, + * this should not deadlock. + */ + LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); + pgrp->pg_jobc = 0; + SLIST_INIT(&pgrp->pg_sigiolst); + PGRP_UNLOCK(pgrp); + + doenterpgrp(p, pgrp); + + return (0); +} + +/* + * Move p to an existing process group + */ +int +enterthispgrp(p, pgrp) + register struct proc *p; + struct pgrp *pgrp; +{ + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); + KASSERT(pgrp->pg_session == p->p_session, + ("%s: pgrp's session %p, p->p_session %p.\n", + __func__, + pgrp->pg_session, + p->p_session)); + KASSERT(pgrp != p->p_pgrp, + ("%s: p belongs to pgrp.", __func__)); + + doenterpgrp(p, pgrp); + + return (0); +} + +/* + * Move p to a process group + */ +static void +doenterpgrp(p, pgrp) + struct proc *p; + struct pgrp *pgrp; +{ + struct pgrp *savepgrp; + + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); + + savepgrp = p->p_pgrp; /* * Adjust eligibility of affected pgrps to participate in job control. @@ -363,15 +437,17 @@ enterpgrp(p, pgid, mksess) fixjobc(p, pgrp, 1); fixjobc(p, p->p_pgrp, 0); + PGRP_LOCK(pgrp); + PGRP_LOCK(savepgrp); PROC_LOCK(p); LIST_REMOVE(p, p_pglist); - savegrp = p->p_pgrp; p->p_pgrp = pgrp; - LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); PROC_UNLOCK(p); - if (LIST_EMPTY(&savegrp->pg_members)) - pgdelete(savegrp); - return (0); + LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); + PGRP_UNLOCK(savepgrp); + PGRP_UNLOCK(pgrp); + if (LIST_EMPTY(&savepgrp->pg_members)) + pgdelete(savepgrp); } /* @@ -381,15 +457,19 @@ int leavepgrp(p) register struct proc *p; { - struct pgrp *savegrp; + struct pgrp *savepgrp; + PGRPSESS_XLOCK(); + savepgrp = p->p_pgrp; + PGRP_LOCK(savepgrp); PROC_LOCK(p); LIST_REMOVE(p, p_pglist); - savegrp = p->p_pgrp; p->p_pgrp = NULL; PROC_UNLOCK(p); - if (LIST_EMPTY(&savegrp->pg_members)) - pgdelete(savegrp); + PGRP_UNLOCK(savepgrp); + if (LIST_EMPTY(&savepgrp->pg_members)) + pgdelete(savepgrp); + PGRPSESS_XUNLOCK(); return (0); } @@ -400,6 +480,13 @@ static void pgdelete(pgrp) register struct pgrp *pgrp; { + struct session *savesess; + + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); + + PGRP_LOCK(pgrp); /* * Reset any sigio structures pointing to us as a result of @@ -411,8 +498,16 @@ pgdelete(pgrp) pgrp->pg_session->s_ttyp->t_pgrp == pgrp) pgrp->pg_session->s_ttyp->t_pgrp = NULL; LIST_REMOVE(pgrp, pg_hash); - if (--pgrp->pg_session->s_count == 0) + savesess = pgrp->pg_session; + SESS_LOCK(savesess); + savesess->s_count--; + SESS_UNLOCK(savesess); + PGRP_UNLOCK(pgrp); + if (savesess->s_count == 0) { + mtx_destroy(&savesess->s_mtx); FREE(pgrp->pg_session, M_SESSION); + } + mtx_destroy(&pgrp->pg_mtx); FREE(pgrp, M_PGRP); } @@ -433,19 +528,30 @@ fixjobc(p, pgrp, entering) int entering; { register struct pgrp *hispgrp; - register struct session *mysession = pgrp->pg_session; + register struct session *mysession; + + PGRPSESS_LOCK_ASSERT(SX_LOCKED); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); /* * Check p's parent to see whether p qualifies its own process * group; if so, adjust count for p's process group. */ + mysession = pgrp->pg_session; sx_slock(&proctree_lock); if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && hispgrp->pg_session == mysession) { + PGRP_LOCK(pgrp); if (entering) pgrp->pg_jobc++; - else if (--pgrp->pg_jobc == 0) - orphanpg(pgrp); + else { + --pgrp->pg_jobc; + if (pgrp->pg_jobc == 0) + orphanpg(pgrp); + } + PGRP_UNLOCK(pgrp); } /* @@ -453,15 +559,21 @@ fixjobc(p, pgrp, entering) * their process groups; if so, adjust counts for children's * process groups. */ - LIST_FOREACH(p, &p->p_children, p_sibling) + LIST_FOREACH(p, &p->p_children, p_sibling) { if ((hispgrp = p->p_pgrp) != pgrp && hispgrp->pg_session == mysession && p->p_stat != SZOMB) { + PGRP_LOCK(hispgrp); if (entering) hispgrp->pg_jobc++; - else if (--hispgrp->pg_jobc == 0) - orphanpg(hispgrp); + else { + --hispgrp->pg_jobc; + if (hispgrp->pg_jobc == 0) + orphanpg(hispgrp); + } + PGRP_UNLOCK(hispgrp); } + } sx_sunlock(&proctree_lock); } @@ -476,6 +588,8 @@ orphanpg(pg) { register struct proc *p; + PGRP_LOCK_ASSERT(pg, MA_OWNED); + mtx_lock_spin(&sched_lock); LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (p->p_stat == SSTOP) { @@ -619,6 +733,7 @@ fill_kinfo_proc(p, kp) /* ^^^ XXXKSE */ mtx_unlock_spin(&sched_lock); sp = NULL; + tp = NULL; if (p->p_pgrp) { kp->ki_pgid = p->p_pgrp->pg_id; kp->ki_jobc = p->p_pgrp->pg_jobc; @@ -626,15 +741,18 @@ fill_kinfo_proc(p, kp) if (sp != NULL) { kp->ki_sid = sp->s_sid; + SESS_LOCK(sp); strncpy(kp->ki_login, sp->s_login, sizeof(kp->ki_login) - 1); if (sp->s_ttyvp) kp->ki_kiflag |= KI_CTTY; if (SESS_LEADER(p)) kp->ki_kiflag |= KI_SLEADER; + tp = sp->s_ttyp; + SESS_UNLOCK(sp); } } - if ((p->p_flag & P_CONTROLT) && sp && ((tp = sp->s_ttyp) != NULL)) { + if ((p->p_flag & P_CONTROLT) && tp != NULL) { kp->ki_tdev = dev2udev(tp->t_dev); kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; if (tp->t_session) @@ -768,18 +886,32 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS) case KERN_PROC_PGRP: /* could do this by traversing pgrp */ + PROC_LOCK(p); if (p->p_pgrp == NULL || - p->p_pgrp->pg_id != (pid_t)name[0]) + p->p_pgrp->pg_id != (pid_t)name[0]) { + PROC_UNLOCK(p); continue; + } + PROC_UNLOCK(p); break; case KERN_PROC_TTY: + PROC_LOCK(p); if ((p->p_flag & P_CONTROLT) == 0 || - p->p_session == NULL || - p->p_session->s_ttyp == NULL || + p->p_session == NULL) { + PROC_UNLOCK(p); + continue; + } + SESS_LOCK(p->p_session); + if (p->p_session->s_ttyp == NULL || dev2udev(p->p_session->s_ttyp->t_dev) != - (udev_t)name[0]) + (udev_t)name[0]) { + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); continue; + } + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); break; case KERN_PROC_UID: diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 76b0c72..615709e 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -51,12 +51,12 @@ #include #include #include +#include #include -#include #include +#include #include #include -#include #include #include #include @@ -137,10 +137,13 @@ getpgrp(td, uap) struct getpgrp_args *uap; { struct proc *p = td->td_proc; + int s; - mtx_lock(&Giant); + s = mtx_lock_giant(kern_giant_proc); + PROC_LOCK(p); td->td_retval[0] = p->p_pgrp->pg_id; - mtx_unlock(&Giant); + PROC_UNLOCK(p); + mtx_unlock_giant(s); return (0); } @@ -164,9 +167,11 @@ getpgid(td, uap) s = mtx_lock_giant(kern_giant_proc); error = 0; - if (uap->pid == 0) + if (uap->pid == 0) { + PROC_LOCK(p); td->td_retval[0] = p->p_pgrp->pg_id; - else if ((pt = pfind(uap->pid)) == NULL) + PROC_UNLOCK(p); + } else if ((pt = pfind(uap->pid)) == NULL) error = ESRCH; else { error = p_cansee(p, pt); @@ -197,12 +202,15 @@ getsid(td, uap) struct proc *p = td->td_proc; struct proc *pt; int error; + int s; - mtx_lock(&Giant); + s = mtx_lock_giant(kern_giant_proc); error = 0; - if (uap->pid == 0) + if (uap->pid == 0) { + PROC_LOCK(p); td->td_retval[0] = p->p_session->s_sid; - else if ((pt = pfind(uap->pid)) == NULL) + PROC_UNLOCK(p); + } else if ((pt = pfind(uap->pid)) == NULL) error = ESRCH; else { error = p_cansee(p, pt); @@ -210,7 +218,7 @@ getsid(td, uap) td->td_retval[0] = pt->p_session->s_sid; PROC_UNLOCK(pt); } - mtx_unlock(&Giant); + mtx_unlock_giant(s); return (error); } @@ -365,19 +373,44 @@ setsid(td, uap) register struct thread *td; struct setsid_args *uap; { + struct pgrp *pgrp; int error; struct proc *p = td->td_proc; + struct pgrp *newpgrp; + struct session *newsess; + + error = 0; + pgrp = NULL; mtx_lock(&Giant); - if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) + + MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); + + PGRPSESS_XLOCK(); + + if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { + if (pgrp != NULL) + PGRP_UNLOCK(pgrp); error = EPERM; - else { - (void)enterpgrp(p, p->p_pid, 1); + goto fail; + } else { + (void)enterpgrp(p, p->p_pid, newpgrp, newsess); td->td_retval[0] = p->p_pid; error = 0; } + PGRPSESS_XUNLOCK(); mtx_unlock(&Giant); - return (error); + return (0); + +fail: + PGRPSESS_XUNLOCK(); + + FREE(newpgrp, M_PGRP); + FREE(newsess, M_SESSION); + + mtx_unlock(&Giant); + return (0); } /* @@ -412,57 +445,92 @@ setpgid(td, uap) register struct proc *targp; /* target process */ register struct pgrp *pgrp; /* target pgrp */ int error; + struct pgrp *newpgrp; if (uap->pgid < 0) return (EINVAL); + + error = 0; + mtx_lock(&Giant); - sx_slock(&proctree_lock); + + MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + + PGRPSESS_XLOCK(); + if (uap->pid != 0 && uap->pid != curp->p_pid) { - if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { + sx_slock(&proctree_lock); + if ((targp = pfind(uap->pid)) == NULL) { if (targp) PROC_UNLOCK(targp); + sx_sunlock(&proctree_lock); error = ESRCH; - goto done2; + goto fail; + } + if (!inferior(targp)) { + PROC_UNLOCK(targp); + sx_sunlock(&proctree_lock); + goto fail; } + sx_sunlock(&proctree_lock); if ((error = p_cansee(curproc, targp))) { PROC_UNLOCK(targp); - goto done2; + goto fail; } if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) { PROC_UNLOCK(targp); error = EPERM; - goto done2; + goto fail; } if (targp->p_flag & P_EXEC) { PROC_UNLOCK(targp); error = EACCES; - goto done2; + goto fail; } - } else { + PROC_UNLOCK(targp); + } else targp = curp; - PROC_LOCK(curp); /* XXX: not needed */ - } if (SESS_LEADER(targp)) { - PROC_UNLOCK(targp); error = EPERM; - goto done2; + goto fail; } if (uap->pgid == 0) uap->pgid = targp->p_pid; - else if (uap->pgid != targp->p_pid) { - if ((pgrp = pgfind(uap->pgid)) == 0 || + if (uap->pgid == targp->p_pid) { + if (targp->p_pgid == uap->pgid) + goto done; + error = enterpgrp(targp, uap->pgid, newpgrp, NULL); + if (error == 0) + newpgrp = NULL; + } else { + if ((pgrp = pgfind(uap->pgid)) == NULL || pgrp->pg_session != curp->p_session) { - PROC_UNLOCK(targp); + if (pgrp != NULL) + PGRP_UNLOCK(pgrp); error = EPERM; - goto done2; + goto fail; + } + if (pgrp == targp->p_pgrp) { + PGRP_UNLOCK(pgrp); + goto done; } + PGRP_UNLOCK(pgrp); + error = enterthispgrp(targp, pgrp); } - /* XXX: We should probably hold the lock across enterpgrp. */ - PROC_UNLOCK(targp); - error = enterpgrp(targp, uap->pgid, 0); -done2: - sx_sunlock(&proctree_lock); +done: + PGRPSESS_XUNLOCK(); + if (newpgrp != NULL) + FREE(newpgrp, M_PGRP); + mtx_unlock(&Giant); + return (0); + +fail: + PGRPSESS_XUNLOCK(); + + KASSERT(newpgrp != NULL, ("setpgid failed and newpgrp is null.")); + FREE(newpgrp, M_PGRP); + mtx_unlock(&Giant); return (error); } @@ -1134,7 +1202,9 @@ issetugid(td, uap) * a user without an exec - programs cannot know *everything* * that libc *might* have put in their data segment. */ + PROC_LOCK(p); td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; + PROC_UNLOCK(p); return (0); } @@ -1153,10 +1223,14 @@ __setugid(td, uap) error = 0; switch (uap->flag) { case 0: + PROC_LOCK(td->td_proc); td->td_proc->p_flag &= ~P_SUGID; + PROC_UNLOCK(td->td_proc); break; case 1: + PROC_LOCK(td->td_proc); td->td_proc->p_flag |= P_SUGID; + PROC_UNLOCK(td->td_proc); break; default: error = EINVAL; @@ -1725,13 +1799,18 @@ getlogin(td, uap) struct getlogin_args *uap; { int error; + char login[MAXLOGNAME]; struct proc *p = td->td_proc; mtx_lock(&Giant); if (uap->namelen > MAXLOGNAME) uap->namelen = MAXLOGNAME; - error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, - (caddr_t) uap->namebuf, uap->namelen); + PROC_LOCK(p); + SESS_LOCK(p->p_session); + bcopy(p->p_session->s_login, login, uap->namelen); + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + error = copyout((caddr_t) login, (caddr_t) uap->namebuf, uap->namelen); mtx_unlock(&Giant); return(error); } @@ -1764,9 +1843,16 @@ setlogin(td, uap) sizeof(logintmp), (size_t *)0); if (error == ENAMETOOLONG) error = EINVAL; - else if (!error) - (void)memcpy(p->p_pgrp->pg_session->s_login, logintmp, + else if (!error) { + PGRPSESS_XLOCK(); + PROC_LOCK(p); + SESS_LOCK(p->p_session); + (void) memcpy(p->p_session->s_login, logintmp, sizeof(logintmp)); + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + PGRPSESS_XUNLOCK(); + } done2: mtx_unlock(&Giant); return (error); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index ffcd488..c15c631 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -111,14 +111,25 @@ getpriority(td, uap) case PRIO_PGRP: { register struct pgrp *pg; - if (uap->who == 0) + PGRPSESS_SLOCK(); + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) - break; + PGRP_LOCK(pg); + } else { + pg = pgfind(uap->who); + if (pg == NULL) { + PGRPSESS_SUNLOCK(); + break; + } + } + PGRPSESS_SUNLOCK(); LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); if (!p_cansee(curp, p) && p->p_ksegrp.kg_nice /* XXXKSE */ < low) low = p->p_ksegrp.kg_nice /* XXXKSE */ ; + PROC_UNLOCK(p); } + PGRP_UNLOCK(pg); break; } @@ -185,16 +196,27 @@ setpriority(td, uap) case PRIO_PGRP: { register struct pgrp *pg; - if (uap->who == 0) + PGRPSESS_SLOCK(); + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) - break; + PGRP_LOCK(pg); + } else { + pg = pgfind(uap->who); + if (pg == NULL) { + PGRPSESS_SUNLOCK(); + break; + } + } + PGRPSESS_SUNLOCK(); LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); if (!p_cansee(curp, p)) { error = donice(curp, p, uap->prio); found++; } + PROC_UNLOCK(p); } + PGRP_UNLOCK(pg); break; } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 27acc64..f871cd5 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1001,16 +1001,21 @@ killpg1(cp, sig, pgid, all) } sx_sunlock(&allproc_lock); } else { - if (pgid == 0) + PGRPSESS_SLOCK(); + if (pgid == 0) { /* * zero pgid means send to my process group. */ pgrp = cp->p_pgrp; - else { + PGRP_LOCK(pgrp); + } else { pgrp = pgfind(pgid); - if (pgrp == NULL) + if (pgrp == NULL) { + PGRPSESS_SUNLOCK(); return (ESRCH); + } } + PGRPSESS_SUNLOCK(); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (p->p_pid <= 1 || p->p_flag & P_SYSTEM) { @@ -1031,6 +1036,7 @@ killpg1(cp, sig, pgid, all) } PROC_UNLOCK(p); } + PGRP_UNLOCK(pgrp); } return (nfound ? 0 : ESRCH); } @@ -1124,8 +1130,15 @@ gsignal(pgid, sig) { struct pgrp *pgrp; - if (pgid && (pgrp = pgfind(pgid))) - pgsignal(pgrp, sig, 0); + if (pgid != 0) { + PGRPSESS_SLOCK(); + pgrp = pgfind(pgid); + PGRPSESS_SUNLOCK(); + if (pgrp != NULL) { + pgsignal(pgrp, sig, 0); + PGRP_UNLOCK(pgrp); + } + } } /* @@ -1140,6 +1153,7 @@ pgsignal(pgrp, sig, checkctty) register struct proc *p; if (pgrp) { + PGRP_LOCK_ASSERT(pgrp, MA_OWNED); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (checkctty == 0 || p->p_flag & P_CONTROLT) @@ -1351,11 +1365,10 @@ psignal(p, sig) goto out; SIGDELSET(p->p_siglist, sig); p->p_xstat = sig; - if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) { - PROC_LOCK(p->p_pptr); + PROC_LOCK(p->p_pptr); + if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); - PROC_UNLOCK(p->p_pptr); - } + PROC_UNLOCK(p->p_pptr); mtx_lock_spin(&sched_lock); stop(p); mtx_unlock_spin(&sched_lock); @@ -1629,14 +1642,13 @@ issignal(p) if (prop & SA_STOP) { if (p->p_flag & P_TRACED || (p->p_pgrp->pg_jobc == 0 && - prop & SA_TTYSTOP)) + prop & SA_TTYSTOP)) break; /* == ignore */ p->p_xstat = sig; - if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) { - PROC_LOCK(p->p_pptr); + PROC_LOCK(p->p_pptr); + if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); - PROC_UNLOCK(p->p_pptr); - } + PROC_UNLOCK(p->p_pptr); mtx_lock_spin(&sched_lock); stop(p); PROC_UNLOCK(p); @@ -2074,7 +2086,7 @@ pgsigio(sigio, sig, checkctty) { if (sigio == NULL) return; - + if (sigio->sio_pgid > 0) { PROC_LOCK(sigio->sio_proc); if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc->p_ucred)) @@ -2083,6 +2095,7 @@ pgsigio(sigio, sig, checkctty) } else if (sigio->sio_pgid < 0) { struct proc *p; + PGRP_LOCK(sigio->sio_pgrp); LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (CANSIGIO(sigio->sio_ucred, p->p_ucred) && @@ -2090,6 +2103,7 @@ pgsigio(sigio, sig, checkctty) psignal(p, sig); PROC_UNLOCK(p); } + PGRP_UNLOCK(sigio->sio_pgrp); } } diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index daa38e4..034a63c 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -41,6 +41,9 @@ #include #include +#include +#include +#include #include #include #include @@ -113,16 +116,28 @@ uprintf(const char *fmt, ...) struct proc *p = td->td_proc; va_list ap; struct putchar_arg pca; - int retval = 0; + int retval; + + if (td == NULL || td == PCPU_GET(idlethread)) + return (0); - if (td && td != PCPU_GET(idlethread) && p->p_flag & P_CONTROLT && - p->p_session->s_ttyvp) { - va_start(ap, fmt); - pca.tty = p->p_session->s_ttyp; - pca.flags = TOTTY; - retval = kvprintf(fmt, putchar, &pca, 10, ap); - va_end(ap); + p = td->td_proc; + PROC_LOCK(p); + if ((p->p_flag & P_CONTROLT) == 0) { + PROC_UNLOCK(p); + return (0); } + SESS_LOCK(p->p_session); + pca.tty = p->p_session->s_ttyp; + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + if (pca.tty == NULL) + return (0); + pca.flags = TOTTY; + va_start(ap, fmt); + retval = kvprintf(fmt, putchar, &pca, 10, ap); + va_end(ap); + return (retval); } @@ -141,13 +156,23 @@ tprintf(struct proc *p, int pri, const char *fmt, ...) if (pri != -1) flags |= TOLOG; - if (p && p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { - SESSHOLD(p->p_session); - shld++; - if (ttycheckoutq(p->p_session->s_ttyp, 0)) { - flags |= TOTTY; + if (p != NULL) { + PGRPSESS_XLOCK(); + PROC_LOCK(p); + if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { + SESS_LOCK(p->p_session); + SESSHOLD(p->p_session); tp = p->p_session->s_ttyp; - } + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + shld++; + if (ttycheckoutq(tp, 0)) + flags |= TOTTY; + else + tp = NULL; + } else + PROC_UNLOCK(p); + PGRPSESS_XUNLOCK(); } pca.pri = pri; pca.tty = tp; @@ -155,8 +180,13 @@ tprintf(struct proc *p, int pri, const char *fmt, ...) va_start(ap, fmt); retval = kvprintf(fmt, putchar, &pca, 10, ap); va_end(ap); - if (shld) + if (shld) { + PGRPSESS_XLOCK(); + SESS_LOCK(p->p_session); SESSRELE(p->p_session); + SESS_UNLOCK(p->p_session); + PGRPSESS_XUNLOCK(); + } msgbuftrigger = 1; } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 4bb6a70..39e3243 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -188,9 +188,12 @@ static struct lock_list_entry w_locklistdata[LOCK_CHILDCOUNT]; static struct witness_order_list_entry order_lists[] = { { "Giant", &lock_class_mtx_sleep }, + { "pgrpsess", &lock_class_sx }, { "proctree", &lock_class_sx }, { "allproc", &lock_class_sx }, + { "process group", &lock_class_mtx_sleep }, { "process lock", &lock_class_mtx_sleep }, + { "session", &lock_class_mtx_sleep }, { "uidinfo hash", &lock_class_mtx_sleep }, { "uidinfo struct", &lock_class_mtx_sleep }, { NULL, NULL }, @@ -227,6 +230,7 @@ static struct witness_order_list_entry order_lists[] = { static const char *dup_list[] = { "process lock", + "process group", NULL }; diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 018734e..e15f191 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -515,10 +515,10 @@ ptrace(struct thread *td, struct ptrace_args *uap) struct proc *pp; pp = pfind(p->p_oppid); - if (pp != NULL) - PROC_UNLOCK(pp); - else + if (pp == NULL) pp = initproc; + else + PROC_UNLOCK(pp); PROC_LOCK(p); proc_reparent(p, pp); } else diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 5c778b7..2ca162a 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -75,6 +75,7 @@ #include #include #include +#include #if defined(COMPAT_43) || defined(COMPAT_SUNOS) #include #endif @@ -328,7 +329,11 @@ ttyinput(c, tp) return (0); if (ISSET(iflag, BRKINT)) { ttyflush(tp, FREAD | FWRITE); - pgsignal(tp->t_pgrp, SIGINT, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGINT, 1); + PGRP_UNLOCK(tp->t_pgrp); + } goto endcase; } if (ISSET(iflag, PARMRK)) @@ -406,15 +411,23 @@ parmrk: if (!ISSET(lflag, NOFLSH)) ttyflush(tp, FREAD | FWRITE); ttyecho(c, tp); - pgsignal(tp->t_pgrp, - CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, + CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); + PGRP_UNLOCK(tp->t_pgrp); + } goto endcase; } if (CCEQ(cc[VSUSP], c)) { if (!ISSET(lflag, NOFLSH)) ttyflush(tp, FREAD); ttyecho(c, tp); - pgsignal(tp->t_pgrp, SIGTSTP, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGTSTP, 1); + PGRP_UNLOCK(tp->t_pgrp); + } goto endcase; } } @@ -532,8 +545,11 @@ parmrk: * ^T - kernel info and generate SIGINFO */ if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) { - if (ISSET(lflag, ISIG)) + if (ISSET(lflag, ISIG) && tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); pgsignal(tp->t_pgrp, SIGINFO, 1); + PGRP_UNLOCK(tp->t_pgrp); + } if (!ISSET(lflag, NOKERNINFO)) ttyinfo(tp); goto endcase; @@ -752,17 +768,30 @@ ttioctl(tp, cmd, data, flag) case TIOCSETP: case TIOCSLTC: #endif + PGRPSESS_SLOCK(); + PROC_LOCK(p); while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) && !SIGISMEMBER(p->p_sigignore, SIGTTOU) && !SIGISMEMBER(p->p_sigmask, SIGTTOU)) { - if (p->p_pgrp->pg_jobc == 0) + if (p->p_pgrp->pg_jobc == 0) { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); return (EIO); + } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); pgsignal(p->p_pgrp, SIGTTOU, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1", 0); - if (error) + if (error) { + PGRPSESS_SUNLOCK(); return (error); + } + PROC_LOCK(p); } + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); break; } @@ -1012,22 +1041,44 @@ ttioctl(tp, cmd, data, flag) break; case TIOCSCTTY: /* become controlling tty */ /* Session ctty vnode pointer set in vnode layer. */ + PGRPSESS_XLOCK(); if (!SESS_LEADER(p) || ((p->p_session->s_ttyvp || tp->t_session) && - (tp->t_session != p->p_session))) + (tp->t_session != p->p_session))) { + PGRPSESS_XUNLOCK(); return (EPERM); + } tp->t_session = p->p_session; tp->t_pgrp = p->p_pgrp; + SESS_LOCK(p->p_session); p->p_session->s_ttyp = tp; + SESS_UNLOCK(p->p_session); + PROC_LOCK(p); p->p_flag |= P_CONTROLT; + PROC_UNLOCK(p); + PGRPSESS_XUNLOCK(); break; case TIOCSPGRP: { /* set pgrp of tty */ - register struct pgrp *pgrp = pgfind(*(int *)data); - - if (!isctty(p, tp)) + register struct pgrp *pgrp; + + PGRPSESS_SLOCK(); + pgrp = pgfind(*(int *)data); + if (!isctty(p, tp)) { + if (pgrp != NULL) + PGRP_UNLOCK(pgrp); + PGRPSESS_SUNLOCK(); return (ENOTTY); - else if (pgrp == NULL || pgrp->pg_session != p->p_session) + } + if (pgrp == NULL) { + PGRPSESS_SUNLOCK(); return (EPERM); + } + PGRP_UNLOCK(pgrp); + if (pgrp->pg_session != p->p_session) { + PGRPSESS_SUNLOCK(); + return (EPERM); + } + PGRPSESS_SUNLOCK(); tp->t_pgrp = pgrp; break; } @@ -1040,7 +1091,11 @@ ttioctl(tp, cmd, data, flag) if (bcmp((caddr_t)&tp->t_winsize, data, sizeof (struct winsize))) { tp->t_winsize = *(struct winsize *)data; - pgsignal(tp->t_pgrp, SIGWINCH, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(tp->t_pgrp); + } } break; case TIOCSDRAINWAIT: @@ -1459,13 +1514,17 @@ ttymodem(tp, flag) !ISSET(tp->t_cflag, CLOCAL)) { SET(tp->t_state, TS_ZOMBIE); CLR(tp->t_state, TS_CONNECTED); - if (tp->t_session && tp->t_session->s_leader) { - struct proc *p; - - p = tp->t_session->s_leader; - PROC_LOCK(p); - psignal(p, SIGHUP); - PROC_UNLOCK(p); + if (tp->t_session) { + PGRPSESS_SLOCK(); + if (tp->t_session->s_leader) { + struct proc *p; + + p = tp->t_session->s_leader; + PROC_LOCK(p); + psignal(p, SIGHUP); + PROC_UNLOCK(p); + } + PGRPSESS_SUNLOCK(); } ttyflush(tp, FREAD | FWRITE); return (0); @@ -1549,11 +1608,20 @@ loop: */ if (isbackground(p, tp)) { splx(s); + PGRPSESS_SLOCK(); + PROC_LOCK(p); if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || SIGISMEMBER(p->p_sigmask, SIGTTIN) || - (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) + (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); return (EIO); + } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); + PGRPSESS_SUNLOCK(); pgsignal(p->p_pgrp, SIGTTIN, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0); if (error) return (error); @@ -1727,7 +1795,11 @@ slowcase: */ if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) { - pgsignal(tp->t_pgrp, SIGTSTP, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGTSTP, 1); + PGRP_UNLOCK(tp->t_pgrp); + } if (first) { error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg3", 0); @@ -1855,19 +1927,30 @@ loop: * Hang the process if it's in the background. */ p = curproc; + PGRPSESS_SLOCK(); + PROC_LOCK(p); if (isbackground(p, tp) && ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) && !SIGISMEMBER(p->p_sigignore, SIGTTOU) && !SIGISMEMBER(p->p_sigmask, SIGTTOU)) { if (p->p_pgrp->pg_jobc == 0) { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); error = EIO; goto out; } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); + PGRPSESS_SUNLOCK(); pgsignal(p->p_pgrp, SIGTTOU, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0); if (error) goto out; goto loop; + } else { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); } /* * Process the user's data in at most OBUFSIZ chunks. Perform any @@ -2328,38 +2411,44 @@ ttyinfo(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) - ttyprintf(tp, "empty foreground process group\n"); else { - mtx_lock_spin(&sched_lock); - - /* Pick interesting process. */ - for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) - if (proc_compare(pick, p)) - pick = p; - - td = FIRST_THREAD_IN_PROC(pick); - stmp = pick->p_stat == SRUN ? "running" : /* XXXKSE */ - td->td_wmesg ? td->td_wmesg : "iowait"; - calcru(pick, &utime, &stime, NULL); - ltmp = pick->p_stat == SIDL || pick->p_stat == SWAIT || - pick->p_stat == SZOMB ? 0 : - pgtok(vmspace_resident_count(pick->p_vmspace)); - mtx_unlock_spin(&sched_lock); - - ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, - stmp); - - /* Print user time. */ - ttyprintf(tp, "%ld.%02ldu ", - (long)utime.tv_sec, utime.tv_usec / 10000); - - /* Print system time. */ - ttyprintf(tp, "%ld.%02lds ", - (long)stime.tv_sec, stime.tv_usec / 10000); - - /* Print percentage cpu, resident set size. */ - ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp); + PGRP_LOCK(tp->t_pgrp); + if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) { + PGRP_UNLOCK(tp->t_pgrp); + ttyprintf(tp, "empty foreground process group\n"); + } else { + PGRP_UNLOCK(tp->t_pgrp); + mtx_lock_spin(&sched_lock); + + /* Pick interesting process. */ + for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) + if (proc_compare(pick, p)) + pick = p; + + td = FIRST_THREAD_IN_PROC(pick); + stmp = pick->p_stat == SRUN ? "running" : /* XXXKSE */ + td->td_wmesg ? td->td_wmesg : "iowait"; + calcru(pick, &utime, &stime, NULL); + ltmp = pick->p_stat == SIDL || pick->p_stat == SWAIT || + pick->p_stat == SZOMB ? 0 : + pgtok(vmspace_resident_count(pick->p_vmspace)); + mtx_unlock_spin(&sched_lock); + + ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, + stmp); + + /* Print user time. */ + ttyprintf(tp, "%lld.%02ldu ", + utime.tv_sec, utime.tv_usec / 10000); + + /* Print system time. */ + ttyprintf(tp, "%ld.%02lds ", + (long)stime.tv_sec, stime.tv_usec / 10000); + + /* Print percentage cpu, resident set size. */ + ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp); + + } } tp->t_rocount = 0; /* so pending input will be retyped if BS */ } diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index 6f1c0db..b3fcc8d 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -41,6 +41,9 @@ #include "opt_compat.h" #include #include +#include +#include +#include #if defined(COMPAT_43) || defined(COMPAT_SUNOS) #include #endif @@ -237,11 +240,19 @@ ptsread(dev, uio, flag) again: if (pti->pt_flags & PF_REMOTE) { while (isbackground(p, tp)) { + PGRPSESS_SLOCK(); + PROC_LOCK(p); if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || SIGISMEMBER(p->p_sigmask, SIGTTIN) || - p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) + p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) { + PROC_UNLOCK(p); return (EIO); + } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); + PGRPSESS_SUNLOCK(); pgsignal(p->p_pgrp, SIGTTIN, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg", 0); if (error) @@ -715,7 +726,11 @@ ptyioctl(dev, cmd, data, flag, td) return(EINVAL); if ((tp->t_lflag&NOFLSH) == 0) ttyflush(tp, FREAD|FWRITE); - pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); + PGRP_UNLOCK(tp->t_pgrp); + } if ((*(unsigned int *)data == SIGINFO) && ((tp->t_lflag&NOKERNINFO) == 0)) ttyinfo(tp); diff --git a/sys/kern/tty_tty.c b/sys/kern/tty_tty.c index 1c6635c..931da01 100644 --- a/sys/kern/tty_tty.c +++ b/sys/kern/tty_tty.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -80,9 +82,15 @@ cttyopen(dev, flag, mode, td) int flag, mode; struct thread *td; { - struct vnode *ttyvp = cttyvp(td); + struct vnode *ttyvp; int error; + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + if (ttyvp == NULL) return (ENXIO); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); @@ -99,9 +107,15 @@ cttyread(dev, uio, flag) int flag; { struct thread *td = uio->uio_td; - register struct vnode *ttyvp = cttyvp(td); + register struct vnode *ttyvp; int error; + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + if (ttyvp == NULL) return (EIO); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); @@ -118,10 +132,16 @@ cttywrite(dev, uio, flag) int flag; { struct thread *td = uio->uio_td; - struct vnode *ttyvp = cttyvp(uio->uio_td); + struct vnode *ttyvp; struct mount *mp; int error; + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + if (ttyvp == NULL) return (EIO); mp = NULL; @@ -144,18 +164,30 @@ cttyioctl(dev, cmd, addr, flag, td) int flag; struct thread *td; { - struct vnode *ttyvp = cttyvp(td); + struct vnode *ttyvp; + int error; + + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); if (ttyvp == NULL) return (EIO); if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */ return EINVAL; /* to controlling tty -- infinite recursion */ if (cmd == TIOCNOTTY) { - if (!SESS_LEADER(td->td_proc)) { + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + error = 0; + if (!SESS_LEADER(td->td_proc)) td->td_proc->p_flag &= ~P_CONTROLT; - return (0); - } else - return (EINVAL); + else + error = EINVAL; + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + return (error); } return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, td)); } @@ -167,7 +199,13 @@ cttypoll(dev, events, td) int events; struct thread *td; { - struct vnode *ttyvp = cttyvp(td); + struct vnode *ttyvp; + + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); if (ttyvp == NULL) /* try operation to get EOF/failure */ diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 3acdf2b..84c1408 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -741,6 +742,8 @@ aio_daemon(void *uproc) struct proc *curcp, *mycp, *userp; struct vmspace *myvm, *tmpvm; struct thread *td = curthread; + struct pgrp *newpgrp; + struct session *newsess; mtx_lock(&Giant); /* @@ -781,7 +784,12 @@ aio_daemon(void *uproc) mycp->p_fd = NULL; /* The daemon resides in its own pgrp. */ - enterpgrp(mycp, mycp->p_pid, 1); + MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); + + PGRPSESS_XLOCK(); + enterpgrp(mycp, mycp->p_pid, newpgrp, newsess); + PGRPSESS_XUNLOCK(); /* Mark special process type. */ mycp->p_flag |= P_SYSTEM; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index aba87d4..ab3e3c9 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -619,6 +619,7 @@ vn_ioctl(fp, com, data, td) struct thread *td; { register struct vnode *vp = ((struct vnode *)fp->f_data); + struct vnode *vpold; struct vattr vattr; int error; @@ -656,15 +657,23 @@ vn_ioctl(fp, com, data, td) if (error == 0 && com == TIOCSCTTY) { /* Do nothing if reassigning same control tty */ - if (td->td_proc->p_session->s_ttyvp == vp) + PGRPSESS_XLOCK(); + if (td->td_proc->p_session->s_ttyvp == vp) { + PGRPSESS_XUNLOCK(); return (0); + } - /* Get rid of reference to old control tty */ - if (td->td_proc->p_session->s_ttyvp) - vrele(td->td_proc->p_session->s_ttyvp); - - td->td_proc->p_session->s_ttyvp = vp; + vpold = td->td_proc->p_session->s_ttyvp; VREF(vp); + SESS_LOCK(td->td_proc->p_session); + td->td_proc->p_session->s_ttyvp = vp; + SESS_UNLOCK(td->td_proc->p_session); + + PGRPSESS_XUNLOCK(); + + /* Get rid of reference to old control tty */ + if (vpold) + vrele(vpold); } return (error); } -- cgit v1.1