From owner-svn-src-all@freebsd.org Wed Sep 16 21:46:58 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 28F843F2926; Wed, 16 Sep 2020 21:46:58 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4BsDFt0K6Lz4L49; Wed, 16 Sep 2020 21:46:58 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id E2CC51FAE2; Wed, 16 Sep 2020 21:46:57 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 08GLkvjF039727; Wed, 16 Sep 2020 21:46:57 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 08GLkv15039726; Wed, 16 Sep 2020 21:46:57 GMT (envelope-from kib@FreeBSD.org) Message-Id: <202009162146.08GLkv15039726@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 16 Sep 2020 21:46:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r365814 - head/sys/kern X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: head/sys/kern X-SVN-Commit-Revision: 365814 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Sep 2020 21:46:58 -0000 Author: kib Date: Wed Sep 16 21:46:57 2020 New Revision: 365814 URL: https://svnweb.freebsd.org/changeset/base/365814 Log: Fix fixjobc+orhpanage. Orphans affect job control state, we must account for them when changing pg_jobc. Instead of p_pptr, use proc_realparent() to get parent relevant for job control. Use correct calculation of the parent for exiting process. For jobc purposes, we must use realparent, but if it is also exiting, we should fall to reaper, then recursively find non-exiting reaper. Reported by: trasz PR: 249257 Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D26416 Modified: head/sys/kern/kern_proc.c Modified: head/sys/kern/kern_proc.c ============================================================================== --- head/sys/kern/kern_proc.c Wed Sep 16 21:40:32 2020 (r365813) +++ head/sys/kern/kern_proc.c Wed Sep 16 21:46:57 2020 (r365814) @@ -645,6 +645,35 @@ isjobproc(struct proc *q, struct pgrp *pgrp) q->p_pgrp->pg_session == pgrp->pg_session); } +static struct proc * +jobc_reaper(struct proc *p) +{ + struct proc *pp; + + sx_assert(&proctree_lock, SX_LOCKED); + + for (pp = p;;) { + pp = pp->p_reaper; + if (pp->p_reaper == pp || + (pp->p_treeflag & P_TREE_GRPEXITED) == 0) + return (pp); + } +} + +static struct proc * +jobc_parent(struct proc *p) +{ + struct proc *pp; + + sx_assert(&proctree_lock, SX_LOCKED); + + pp = proc_realparent(p); + if (pp->p_pptr == NULL || + (pp->p_treeflag & P_TREE_GRPEXITED) == 0) + return (pp); + return (jobc_reaper(pp)); +} + #ifdef INVARIANTS static void check_pgrp_jobc(struct pgrp *pgrp) @@ -661,7 +690,7 @@ check_pgrp_jobc(struct pgrp *pgrp) if ((q->p_treeflag & P_TREE_GRPEXITED) != 0 || q->p_pptr == NULL) continue; - if (isjobproc(q->p_pptr, pgrp)) + if (isjobproc(jobc_parent(q), pgrp)) cnt++; } KASSERT(pgrp->pg_jobc == cnt, ("pgrp %d %p pg_jobc %d cnt %d", @@ -784,6 +813,25 @@ pgadjustjobc(struct pgrp *pgrp, bool entering) PGRP_UNLOCK(pgrp); } +static void +fixjobc_enterpgrp_q(struct pgrp *pgrp, struct proc *p, struct proc *q, bool adj) +{ + struct pgrp *childpgrp; + bool future_jobc; + + sx_assert(&proctree_lock, SX_LOCKED); + + if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) + return; + childpgrp = q->p_pgrp; + future_jobc = childpgrp != pgrp && + childpgrp->pg_session == pgrp->pg_session; + + if ((adj && !isjobproc(p, childpgrp) && future_jobc) || + (!adj && isjobproc(p, childpgrp) && !future_jobc)) + pgadjustjobc(childpgrp, adj); +} + /* * Adjust pgrp jobc counters when specified process changes process group. * We count the number of processes in each process group that "qualify" @@ -798,8 +846,6 @@ static void fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp) { struct proc *q; - struct pgrp *childpgrp; - bool future_jobc; sx_assert(&proctree_lock, SX_LOCKED); PROC_LOCK_ASSERT(p, MA_NOTOWNED); @@ -809,36 +855,49 @@ fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp) if (p->p_pgrp == pgrp) return; - if (isjobproc(p->p_pptr, pgrp)) + if (isjobproc(jobc_parent(p), pgrp)) pgadjustjobc(pgrp, true); LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) + if ((q->p_treeflag & P_TREE_ORPHANED) != 0) continue; - childpgrp = q->p_pgrp; - future_jobc = childpgrp != pgrp && - childpgrp->pg_session == pgrp->pg_session; - if (!isjobproc(p, childpgrp) && future_jobc) - pgadjustjobc(childpgrp, true); + fixjobc_enterpgrp_q(pgrp, p, q, true); } + LIST_FOREACH(q, &p->p_orphans, p_orphan) + fixjobc_enterpgrp_q(pgrp, p, q, true); - if (isjobproc(p->p_pptr, p->p_pgrp)) + if (isjobproc(jobc_parent(p), p->p_pgrp)) pgadjustjobc(p->p_pgrp, false); LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) + if ((q->p_treeflag & P_TREE_ORPHANED) != 0) continue; - childpgrp = q->p_pgrp; - future_jobc = childpgrp != pgrp && - childpgrp->pg_session == pgrp->pg_session; - if (isjobproc(p, childpgrp) && !future_jobc) - pgadjustjobc(childpgrp, false); + fixjobc_enterpgrp_q(pgrp, p, q, false); } + LIST_FOREACH(q, &p->p_orphans, p_orphan) + fixjobc_enterpgrp_q(pgrp, p, q, false); } static void +fixjobc_kill_q(struct proc *p, struct proc *q, bool adj) +{ + struct pgrp *childpgrp; + + sx_assert(&proctree_lock, SX_LOCKED); + + if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) + return; + childpgrp = q->p_pgrp; + + if ((adj && isjobproc(jobc_reaper(q), childpgrp) && + !isjobproc(p, childpgrp)) || (!adj && !isjobproc(jobc_reaper(q), + childpgrp) && isjobproc(p, childpgrp))) + pgadjustjobc(childpgrp, adj); +} + +static void fixjobc_kill(struct proc *p) { struct proc *q; - struct pgrp *childpgrp, *pgrp; + struct pgrp *pgrp; sx_assert(&proctree_lock, SX_LOCKED); PROC_LOCK_ASSERT(p, MA_NOTOWNED); @@ -858,7 +917,7 @@ fixjobc_kill(struct proc *p) * Check p's parent to see whether p qualifies its own process * group; if so, adjust count for p's process group. */ - if (isjobproc(p->p_pptr, pgrp)) + if (isjobproc(jobc_parent(p), pgrp)) pgadjustjobc(pgrp, false); /* @@ -867,21 +926,19 @@ fixjobc_kill(struct proc *p) * adjust counts for children's process groups. */ LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) + if ((q->p_treeflag & P_TREE_ORPHANED) != 0) continue; - childpgrp = q->p_pgrp; - if (isjobproc(q->p_reaper, childpgrp) && - !isjobproc(p, childpgrp)) - pgadjustjobc(childpgrp, true); + fixjobc_kill_q(p, q, true); } + LIST_FOREACH(q, &p->p_orphans, p_orphan) + fixjobc_kill_q(p, q, true); LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) + if ((q->p_treeflag & P_TREE_ORPHANED) != 0) continue; - childpgrp = q->p_pgrp; - if (!isjobproc(q->p_reaper, childpgrp) && - isjobproc(p, childpgrp)) - pgadjustjobc(childpgrp, false); + fixjobc_kill_q(p, q, false); } + LIST_FOREACH(q, &p->p_orphans, p_orphan) + fixjobc_kill_q(p, q, false); } void