Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Jan 2015 03:27:10 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r276686 - in stable/10: lib/libc/sys sys/compat/freebsd32 sys/conf sys/kern sys/sys
Message-ID:  <201501050327.t053RAhp037781@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Jan  5 03:27:09 2015
New Revision: 276686
URL: https://svnweb.freebsd.org/changeset/base/276686

Log:
  Merge reaper facility.
  
  MFC r270443 (by mjg):
  Properly reparent traced processes when the tracer dies.
  
  MFC r273452 (by mjg):
  Plug unnecessary PRS_NEW check in kern_procctl.
  
  MFC 275800:
  Add a facility for non-init process to declare itself the reaper of
  the orphaned descendants.
  
  MFC r275821:
  Add missed break.
  
  MFC r275846 (by mckusick):
  Add some additional clarification and fix a few gammer nits.
  
  MFC r275847 (by bdrewery):
  Bump Dd for r275846.

Added:
  stable/10/sys/kern/kern_procctl.c
     - copied, changed from r275800, head/sys/kern/kern_procctl.c
Modified:
  stable/10/lib/libc/sys/procctl.2
  stable/10/sys/compat/freebsd32/freebsd32.h
  stable/10/sys/compat/freebsd32/freebsd32_misc.c
  stable/10/sys/conf/files
  stable/10/sys/kern/init_main.c
  stable/10/sys/kern/kern_exit.c
  stable/10/sys/kern/kern_fork.c
  stable/10/sys/kern/sys_process.c
  stable/10/sys/sys/proc.h
  stable/10/sys/sys/procctl.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/lib/libc/sys/procctl.2
==============================================================================
--- stable/10/lib/libc/sys/procctl.2	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/lib/libc/sys/procctl.2	Mon Jan  5 03:27:09 2015	(r276686)
@@ -2,6 +2,10 @@
 .\" Written by: John H. Baldwin <jhb@FreeBSD.org>
 .\" All rights reserved.
 .\"
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" Portions of this documentation were written by Konstantin Belousov
+.\" under sponsorship from the FreeBSD Foundation.
+.\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
@@ -25,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 19, 2013
+.Dd December 16, 2014
 .Dt PROCCTL 2
 .Os
 .Sh NAME
@@ -67,7 +71,7 @@ The control request to perform is specif
 .Fa cmd
 argument.
 The following commands are supported:
-.Bl -tag -width "Dv PROC_SPROTECT"
+.Bl -tag -width "Dv PROC_REAP_GETPIDS"
 .It Dv PROC_SPROTECT
 Set process protection state.
 This is used to mark a process as protected from being killed if the system
@@ -95,6 +99,182 @@ When used with
 mark all future child processes of each selected process as protected.
 Future child processes will also mark all of their future child processes.
 .El
+.It Dv PROC_REAP_ACQUIRE
+Acquires the reaper status for the current process.
+The status means that children orphaned by the reaper's descendants
+that were forked after the acquisition of the status are reparented to the
+reaper.
+After the system initialization,
+.Xr init 8
+is the default reaper.
+.Pp
+.It Dv PROC_REAP_RELEASE
+Releases the reaper state for the current process.
+The reaper of the current process becomes the new reaper of the
+current process's descendants.
+.It Dv PROC_REAP_STATUS
+Provides the information about the reaper of the specified process,
+or the process itself when it is a reaper.
+The
+.Fa data
+argument must point to a
+.Vt procctl_reaper_status
+structure which is filled in by the syscall on successful return.
+.Bd -literal
+struct procctl_reaper_status {
+	u_int	rs_flags;
+	u_int	rs_children;
+	u_int	rs_descendants;
+	pid_t	rs_reaper;
+	pid_t	rs_pid;
+};
+.Ed
+The
+.Fa rs_flags
+may have the following flags returned:
+.Bl -tag -width "Dv REAPER_STATUS_REALINIT"
+.It Dv REAPER_STATUS_OWNED
+The specified process has acquired the reaper status and has not
+released it.
+When the flag is returned, the specified process
+.Fa id ,
+pid, identifies the reaper, otherwise the
+.Fa rs_reaper
+field of the structure is set to the pid of the reaper
+for the specified process id.
+.It Dv REAPER_STATUS_REALINIT
+The specified process is the root of the reaper tree, i.e.
+.Xr init 8 .
+.El
+The
+.Fa rs_children
+field returns the number of children of the reaper.
+The
+.Fa rs_descendants
+field returns the total number of descendants of the reaper(s),
+not counting descendants of the reaper in the subtree.
+The
+.Fa rs_reaper
+field returns the reaper pid.
+The
+.Fa rs_pid
+returns the pid of one reaper child if there are any descendants.
+.It Dv PROC_REAP_GETPIDS
+Queries the list of descendants of the reaper of the specified process.
+The request takes a pointer to a
+.Vt procctl_reaper_pids
+structure in the
+.Fa data
+parameter.
+.Bd -literal
+struct procctl_reaper_pids {
+	u_int	rp_count;
+	struct procctl_reaper_pidinfo *rp_pids;
+};
+.Ed
+When called, the
+.Fa rp_pids
+field must point to an array of
+.Vt procctl_reaper_pidinfo
+structures, to be filled in on return,
+and the
+.Fa rp_count
+field must specify the size of the array,
+into which no more than
+.Fa rp_count
+elements will be filled in by the kernel.
+.Pp
+The
+.Vt "struct procctl_reaper_pidinfo"
+structure provides some information about one of the reaper's descendants.
+Note that for a descendant that is not a child, it may be incorrectly
+identified because of a race in which the original child process exited
+and the exited process's pid was reused for an unrelated process.
+.Bd -literal
+struct procctl_reaper_pidinfo {
+	pid_t	pi_pid;
+	pid_t	pi_subtree;
+	u_int	pi_flags;
+};
+.Ed
+The
+.Fa pi_pid
+field is the process id of the descendant.
+The
+.Fa pi_subtree
+field provides the pid of the child of the reaper, which is the (grand-)parent
+of the process.
+The
+.Fa pi_flags
+field returns the following flags, further describing the descendant:
+.Bl -tag -width "Dv REAPER_PIDINFO_VALID"
+.It Dv REAPER_PIDINFO_VALID
+Set to indicate that the
+.Vt procctl_reaper_pidinfo
+structure was filled in by the kernel.
+Zero-filling the
+.Fa rp_pids
+array and testing the
+.Dv REAPER_PIDINFO_VALID
+flag allows the caller to detect the end
+of the returned array.
+.It Dv REAPER_PIDINFO_CHILD
+The
+.Fa pi_pid
+field identifies the direct child of the reaper.
+.El
+.It Dv PROC_REAP_KILL
+Request to deliver a signal to some subset of the descendants of the reaper.
+The
+.Fa data
+parameter must point to a
+.Vt procctl_reaper_kill
+structure, which is used both for parameters and status return.
+.Bd -literal
+struct procctl_reaper_kill {
+	int	rk_sig;
+	u_int	rk_flags;
+	pid_t	rk_subtree;
+	u_int	rk_killed;
+	pid_t	rk_fpid;
+};
+.Ed
+The
+.Fa rk_sig
+field specifies the signal to be delivered.
+Zero is not a valid signal number, unlike
+.Xr kill 2 .
+The
+.Fa rk_flags
+field further directs the operation.
+It is or-ed from the following flags:
+.Bl -tag -width "Dv REAPER_KILL_CHILDREN"
+.It Dv REAPER_KILL_CHILDREN
+Deliver the specified signal only to direct children of the reaper.
+.It Dv REAPER_KILL_SUBTREE
+Deliver the specified signal only to descendants that were forked by
+the direct child with pid specified in the
+.Fa rk_subtree
+field.
+.El
+If neither the
+.Dv REAPER_KILL_CHILDREN
+nor the
+.Dv REAPER_KILL_SUBTREE
+flags are specified, all current descendants of the reaper are signalled.
+.Pp
+If a signal was delivered to any process, the return value from the request
+is zero.
+In this case, the
+.Fa rk_killed
+field identifies the number of processes signalled.
+The
+.Fa rk_fpid
+field is set to the pid of the first process for which signal
+delivery failed, e.g. due to the permission problems.
+If no such process exist, the
+.Fa rk_fpid
+field is set to -1.
 .El
 .Sh RETURN VALUES
 If an error occurs, a value of -1 is returned and
@@ -109,7 +289,7 @@ will fail if:
 .It Bq Er EFAULT
 The
 .Fa arg
-points outside the process's allocated address space.
+parameter points outside the process's allocated address space.
 .It Bq Er EINVAL
 The
 .Fa cmd
@@ -132,11 +312,48 @@ An invalid operation or flag was passed 
 for a
 .Dv PROC_SPROTECT
 command.
+.It Bq Er EPERM
+The
+.Fa idtype
+argument is not equal to
+.Dv P_PID ,
+or
+.Fa id
+is not equal to the pid of the calling process, for
+.Dv PROC_REAP_ACQUIRE
+or
+.Dv PROC_REAP_RELEASE
+requests.
+.It Bq Er EINVAL
+Invalid or undefined flags were passed to a
+.Dv PROC_REAP_KILL
+request.
+.It Bq Er EINVAL
+An invalid or zero signal number was requested for a
+.Dv PROC_REAP_KILL
+request.
+.It Bq Er EINVAL
+The
+.Dv PROC_REAP_RELEASE
+request was issued by the
+.Xr init 8
+process.
+.It Bq Er EBUSY
+The
+.Dv PROC_REAP_ACQUIRE
+request was issued by a process that had already acquired reaper status
+and has not yet released it.
 .El
 .Sh SEE ALSO
-.Xr ptrace 2
+.Xr kill 2 ,
+.Xr ptrace 2 ,
+.Xr wait 2 ,
+.Xr init 8
 .Sh HISTORY
 The
 .Fn procctl
 function appeared in
-.Fx 10 .
+.Fx 10.0 .
+The reaper facility is based on a similar feature of Linux and
+DragonflyBSD, and first appeared in
+.Fx 10.2 .

Modified: stable/10/sys/compat/freebsd32/freebsd32.h
==============================================================================
--- stable/10/sys/compat/freebsd32/freebsd32.h	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/compat/freebsd32/freebsd32.h	Mon Jan  5 03:27:09 2015	(r276686)
@@ -387,4 +387,10 @@ struct kld32_file_stat {
 	char	pathname[MAXPATHLEN];
 };
 
+struct procctl_reaper_pids32 {
+	u_int	rp_count;
+	u_int	rp_pad0[15];
+	uint32_t rp_pids;
+};
+
 #endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */

Modified: stable/10/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- stable/10/sys/compat/freebsd32/freebsd32_misc.c	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/compat/freebsd32/freebsd32_misc.c	Mon Jan  5 03:27:09 2015	(r276686)
@@ -3062,20 +3062,63 @@ int
 freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
 {
 	void *data;
-	int error, flags;
+	union {
+		struct procctl_reaper_status rs;
+		struct procctl_reaper_pids rp;
+		struct procctl_reaper_kill rk;
+	} x;
+	union {
+		struct procctl_reaper_pids32 rp;
+	} x32;
+	int error, error1, flags;
 
 	switch (uap->com) {
 	case PROC_SPROTECT:
 		error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
-		if (error)
+		if (error != 0)
 			return (error);
 		data = &flags;
 		break;
+	case PROC_REAP_ACQUIRE:
+	case PROC_REAP_RELEASE:
+		if (uap->data != NULL)
+			return (EINVAL);
+		data = NULL;
+		break;
+	case PROC_REAP_STATUS:
+		data = &x.rs;
+		break;
+	case PROC_REAP_GETPIDS:
+		error = copyin(uap->data, &x32.rp, sizeof(x32.rp));
+		if (error != 0)
+			return (error);
+		CP(x32.rp, x.rp, rp_count);
+		PTRIN_CP(x32.rp, x.rp, rp_pids);
+		data = &x.rp;
+		break;
+	case PROC_REAP_KILL:
+		error = copyin(uap->data, &x.rk, sizeof(x.rk));
+		if (error != 0)
+			return (error);
+		data = &x.rk;
+		break;
 	default:
 		return (EINVAL);
 	}
-	return (kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id),
-	    uap->com, data));
+	error = kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id),
+	    uap->com, data);
+	switch (uap->com) {
+	case PROC_REAP_STATUS:
+		if (error == 0)
+			error = copyout(&x.rs, uap->data, sizeof(x.rs));
+		break;
+	case PROC_REAP_KILL:
+		error1 = copyout(&x.rk, uap->data, sizeof(x.rk));
+		if (error == 0)
+			error = error1;
+		break;
+	}
+	return (error);
 }
 
 int

Modified: stable/10/sys/conf/files
==============================================================================
--- stable/10/sys/conf/files	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/conf/files	Mon Jan  5 03:27:09 2015	(r276686)
@@ -2916,6 +2916,7 @@ kern/kern_pmc.c			standard
 kern/kern_poll.c		optional device_polling
 kern/kern_priv.c		standard
 kern/kern_proc.c		standard
+kern/kern_procctl.c		standard
 kern/kern_prot.c		standard
 kern/kern_racct.c		standard
 kern/kern_rangelock.c		standard

Modified: stable/10/sys/kern/init_main.c
==============================================================================
--- stable/10/sys/kern/init_main.c	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/kern/init_main.c	Mon Jan  5 03:27:09 2015	(r276686)
@@ -496,7 +496,8 @@ proc0_init(void *dummy __unused)
 	prison0.pr_cpuset = cpuset_ref(td->td_cpuset);
 	p->p_peers = 0;
 	p->p_leader = p;
-
+	p->p_reaper = p;
+	LIST_INIT(&p->p_reaplist);
 
 	strncpy(p->p_comm, "kernel", sizeof (p->p_comm));
 	strncpy(td->td_name, "swapper", sizeof (td->td_name));
@@ -821,8 +822,11 @@ create_init(const void *udata __unused)
 	KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1"));
 	/* divorce init's credentials from the kernel's */
 	newcred = crget();
+	sx_xlock(&proctree_lock);
 	PROC_LOCK(initproc);
 	initproc->p_flag |= P_SYSTEM | P_INMEM;
+	initproc->p_treeflag |= P_TREE_REAPER;
+	LIST_INSERT_HEAD(&initproc->p_reaplist, &proc0, p_reapsibling);
 	oldcred = initproc->p_ucred;
 	crcopy(newcred, oldcred);
 #ifdef MAC
@@ -833,6 +837,7 @@ create_init(const void *udata __unused)
 #endif
 	initproc->p_ucred = newcred;
 	PROC_UNLOCK(initproc);
+	sx_xunlock(&proctree_lock);
 	crfree(oldcred);
 	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
 	cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);

Modified: stable/10/sys/kern/kern_exit.c
==============================================================================
--- stable/10/sys/kern/kern_exit.c	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/kern/kern_exit.c	Mon Jan  5 03:27:09 2015	(r276686)
@@ -125,6 +125,31 @@ proc_realparent(struct proc *child)
 	return (parent);
 }
 
+void
+reaper_abandon_children(struct proc *p, bool exiting)
+{
+	struct proc *p1, *p2, *ptmp;
+
+	sx_assert(&proctree_lock, SX_LOCKED);
+	KASSERT(p != initproc, ("reaper_abandon_children for initproc"));
+	if ((p->p_treeflag & P_TREE_REAPER) == 0)
+		return;
+	p1 = p->p_reaper;
+	LIST_FOREACH_SAFE(p2, &p->p_reaplist, p_reapsibling, ptmp) {
+		LIST_REMOVE(p2, p_reapsibling);
+		p2->p_reaper = p1;
+		p2->p_reapsubtree = p->p_reapsubtree;
+		LIST_INSERT_HEAD(&p1->p_reaplist, p2, p_reapsibling);
+		if (exiting && p2->p_pptr == p) {
+			PROC_LOCK(p2);
+			proc_reparent(p2, p1);
+			PROC_UNLOCK(p2);
+		}
+	}
+	KASSERT(LIST_EMPTY(&p->p_reaplist), ("p_reaplist not empty"));
+	p->p_treeflag &= ~P_TREE_REAPER;
+}
+
 static void
 clear_orphan(struct proc *p)
 {
@@ -162,7 +187,8 @@ sys_sys_exit(struct thread *td, struct s
 void
 exit1(struct thread *td, int rv)
 {
-	struct proc *p, *nq, *q;
+	struct proc *p, *nq, *q, *t;
+	struct thread *tdt;
 	struct vnode *ttyvp = NULL;
 
 	mtx_assert(&Giant, MA_NOTOWNED);
@@ -450,24 +476,34 @@ exit1(struct thread *td, int rv)
 	WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid);
 
 	/*
-	 * Reparent all of our children to init.
+	 * Reparent all children processes:
+	 * - traced ones to the original parent (or init if we are that parent)
+	 * - the rest to init
 	 */
 	sx_xlock(&proctree_lock);
 	q = LIST_FIRST(&p->p_children);
 	if (q != NULL)		/* only need this if any child is S_ZOMB */
-		wakeup(initproc);
+		wakeup(q->p_reaper);
 	for (; q != NULL; q = nq) {
 		nq = LIST_NEXT(q, p_sibling);
 		PROC_LOCK(q);
-		proc_reparent(q, initproc);
 		q->p_sigparent = SIGCHLD;
-		/*
-		 * Traced processes are killed
-		 * since their existence means someone is screwing up.
-		 */
-		if (q->p_flag & P_TRACED) {
-			struct thread *temp;
 
+		if (!(q->p_flag & P_TRACED)) {
+			proc_reparent(q, q->p_reaper);
+		} else {
+			/*
+			 * Traced processes are killed since their existence
+			 * means someone is screwing up.
+			 */
+			t = proc_realparent(q);
+			if (t == p) {
+				proc_reparent(q, q->p_reaper);
+			} else {
+				PROC_LOCK(t);
+				proc_reparent(q, t);
+				PROC_UNLOCK(t);
+			}
 			/*
 			 * Since q was found on our children list, the
 			 * proc_reparent() call moved q to the orphan
@@ -476,8 +512,8 @@ exit1(struct thread *td, int rv)
 			 */
 			clear_orphan(q);
 			q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
-			FOREACH_THREAD_IN_PROC(q, temp)
-				temp->td_dbgflags &= ~TDB_SUSPEND;
+			FOREACH_THREAD_IN_PROC(q, tdt)
+				tdt->td_dbgflags &= ~TDB_SUSPEND;
 			kern_psignal(q, SIGKILL);
 		}
 		PROC_UNLOCK(q);
@@ -553,7 +589,7 @@ exit1(struct thread *td, int rv)
 			mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
 			pp = p->p_pptr;
 			PROC_UNLOCK(pp);
-			proc_reparent(p, initproc);
+			proc_reparent(p, p->p_reaper);
 			p->p_sigparent = SIGCHLD;
 			PROC_LOCK(p->p_pptr);
 
@@ -566,8 +602,8 @@ exit1(struct thread *td, int rv)
 		} else
 			mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
 
-		if (p->p_pptr == initproc)
-			kern_psignal(p->p_pptr, SIGCHLD);
+		if (p->p_pptr == p->p_reaper || p->p_pptr == initproc)
+			childproc_exited(p);
 		else if (p->p_sigparent != 0) {
 			if (p->p_sigparent == SIGCHLD)
 				childproc_exited(p);
@@ -840,6 +876,8 @@ proc_reap(struct thread *td, struct proc
 	LIST_REMOVE(p, p_list);	/* off zombproc */
 	sx_xunlock(&allproc_lock);
 	LIST_REMOVE(p, p_sibling);
+	reaper_abandon_children(p, true);
+	LIST_REMOVE(p, p_reapsibling);
 	PROC_LOCK(p);
 	clear_orphan(p);
 	PROC_UNLOCK(p);

Modified: stable/10/sys/kern/kern_fork.c
==============================================================================
--- stable/10/sys/kern/kern_fork.c	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/kern/kern_fork.c	Mon Jan  5 03:27:09 2015	(r276686)
@@ -267,11 +267,21 @@ retry:
 		 * Scan the active and zombie procs to check whether this pid
 		 * is in use.  Remember the lowest pid that's greater
 		 * than trypid, so we can avoid checking for a while.
+		 *
+		 * Avoid reuse of the process group id, session id or
+		 * the reaper subtree id.  Note that for process group
+		 * and sessions, the amount of reserved pids is
+		 * limited by process limit.  For the subtree ids, the
+		 * id is kept reserved only while there is a
+		 * non-reaped process in the subtree, so amount of
+		 * reserved pids is limited by process limit times
+		 * two.
 		 */
 		p = LIST_FIRST(&allproc);
 again:
 		for (; p != NULL; p = LIST_NEXT(p, p_list)) {
 			while (p->p_pid == trypid ||
+			    p->p_reapsubtree == trypid ||
 			    (p->p_pgrp != NULL &&
 			    (p->p_pgrp->pg_id == trypid ||
 			    (p->p_session != NULL &&
@@ -618,12 +628,22 @@ do_fork(struct thread *td, int flags, st
 	 * of init.  This effectively disassociates the child from the
 	 * parent.
 	 */
-	if (flags & RFNOWAIT)
-		pptr = initproc;
-	else
+	if ((flags & RFNOWAIT) != 0) {
+		pptr = p1->p_reaper;
+		p2->p_reaper = pptr;
+	} else {
+		p2->p_reaper = (p1->p_treeflag & P_TREE_REAPER) != 0 ?
+		    p1 : p1->p_reaper;
 		pptr = p1;
+	}
 	p2->p_pptr = pptr;
 	LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling);
+	LIST_INIT(&p2->p_reaplist);
+	LIST_INSERT_HEAD(&p2->p_reaper->p_reaplist, p2, p_reapsibling);
+	if (p2->p_reaper == p1)
+		p2->p_reapsubtree = p2->p_pid;
+	else
+		p2->p_reapsubtree = p1->p_reapsubtree;		
 	sx_xunlock(&proctree_lock);
 
 	/* Inform accounting that we have forked. */

Copied and modified: stable/10/sys/kern/kern_procctl.c (from r275800, head/sys/kern/kern_procctl.c)
==============================================================================
--- head/sys/kern/kern_procctl.c	Mon Dec 15 12:01:42 2014	(r275800, copy source)
+++ stable/10/sys/kern/kern_procctl.c	Mon Jan  5 03:27:09 2015	(r276686)
@@ -32,7 +32,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/capsicum.h>
+#include <sys/capability.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/priv.h>
@@ -336,6 +336,7 @@ sys_procctl(struct thread *td, struct pr
 	case PROC_REAP_STATUS:
 		if (error == 0)
 			error = copyout(&x.rs, uap->data, sizeof(x.rs));
+		break;
 	case PROC_REAP_KILL:
 		error1 = copyout(&x.rk, uap->data, sizeof(x.rk));
 		if (error == 0)

Modified: stable/10/sys/kern/sys_process.c
==============================================================================
--- stable/10/sys/kern/sys_process.c	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/kern/sys_process.c	Mon Jan  5 03:27:09 2015	(r276686)
@@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysproto.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
-#include <sys/procctl.h>
 #include <sys/vnode.h>
 #include <sys/ptrace.h>
 #include <sys/rwlock.h>
@@ -1234,196 +1233,3 @@ stopevent(struct proc *p, unsigned int e
 		msleep(&p->p_step, &p->p_mtx, PWAIT, "stopevent", 0);
 	} while (p->p_step);
 }
-
-static int
-protect_setchild(struct thread *td, struct proc *p, int flags)
-{
-
-	PROC_LOCK_ASSERT(p, MA_OWNED);
-	if (p->p_flag & P_SYSTEM || p_cansched(td, p) != 0)
-		return (0);
-	if (flags & PPROT_SET) {
-		p->p_flag |= P_PROTECTED;
-		if (flags & PPROT_INHERIT)
-			p->p_flag2 |= P2_INHERIT_PROTECTED;
-	} else {
-		p->p_flag &= ~P_PROTECTED;
-		p->p_flag2 &= ~P2_INHERIT_PROTECTED;
-	}
-	return (1);
-}
-
-static int
-protect_setchildren(struct thread *td, struct proc *top, int flags)
-{
-	struct proc *p;
-	int ret;
-
-	p = top;
-	ret = 0;
-	sx_assert(&proctree_lock, SX_LOCKED);
-	for (;;) {
-		ret |= protect_setchild(td, p, flags);
-		PROC_UNLOCK(p);
-		/*
-		 * If this process has children, descend to them next,
-		 * otherwise do any siblings, and if done with this level,
-		 * follow back up the tree (but not past top).
-		 */
-		if (!LIST_EMPTY(&p->p_children))
-			p = LIST_FIRST(&p->p_children);
-		else for (;;) {
-			if (p == top) {
-				PROC_LOCK(p);
-				return (ret);
-			}
-			if (LIST_NEXT(p, p_sibling)) {
-				p = LIST_NEXT(p, p_sibling);
-				break;
-			}
-			p = p->p_pptr;
-		}
-		PROC_LOCK(p);
-	}
-}
-
-static int
-protect_set(struct thread *td, struct proc *p, int flags)
-{
-	int error, ret;
-
-	switch (PPROT_OP(flags)) {
-	case PPROT_SET:
-	case PPROT_CLEAR:
-		break;
-	default:
-		return (EINVAL);
-	}
-
-	if ((PPROT_FLAGS(flags) & ~(PPROT_DESCEND | PPROT_INHERIT)) != 0)
-		return (EINVAL);
-
-	error = priv_check(td, PRIV_VM_MADV_PROTECT);
-	if (error)
-		return (error);
-
-	if (flags & PPROT_DESCEND)
-		ret = protect_setchildren(td, p, flags);
-	else
-		ret = protect_setchild(td, p, flags);
-	if (ret == 0)
-		return (EPERM);
-	return (0);
-}
-
-#ifndef _SYS_SYSPROTO_H_
-struct procctl_args {
-	idtype_t idtype;
-	id_t	id;
-	int	com;
-	void	*data;
-};
-#endif
-/* ARGSUSED */
-int
-sys_procctl(struct thread *td, struct procctl_args *uap)
-{
-	int error, flags;
-	void *data;
-
-	switch (uap->com) {
-	case PROC_SPROTECT:
-		error = copyin(uap->data, &flags, sizeof(flags));
-		if (error)
-			return (error);
-		data = &flags;
-		break;
-	default:
-		return (EINVAL);
-	}
-
-	return (kern_procctl(td, uap->idtype, uap->id, uap->com, data));
-}
-
-static int
-kern_procctl_single(struct thread *td, struct proc *p, int com, void *data)
-{
-
-	PROC_LOCK_ASSERT(p, MA_OWNED);
-	switch (com) {
-	case PROC_SPROTECT:
-		return (protect_set(td, p, *(int *)data));
-	default:
-		return (EINVAL);
-	}
-}
-
-int
-kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
-{
-	struct pgrp *pg;
-	struct proc *p;
-	int error, first_error, ok;
-
-	sx_slock(&proctree_lock);
-	switch (idtype) {
-	case P_PID:
-		p = pfind(id);
-		if (p == NULL) {
-			error = ESRCH;
-			break;
-		}
-		if (p->p_state == PRS_NEW)
-			error = ESRCH;
-		else
-			error = p_cansee(td, p);
-		if (error == 0)
-			error = kern_procctl_single(td, p, com, data);
-		PROC_UNLOCK(p);
-		break;
-	case P_PGID:
-		/*
-		 * Attempt to apply the operation to all members of the
-		 * group.  Ignore processes in the group that can't be
-		 * seen.  Ignore errors so long as at least one process is
-		 * able to complete the request successfully.
-		 */
-		pg = pgfind(id);
-		if (pg == NULL) {
-			error = ESRCH;
-			break;
-		}
-		PGRP_UNLOCK(pg);
-		ok = 0;
-		first_error = 0;
-		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
-			PROC_LOCK(p);
-			if (p->p_state == PRS_NEW || p_cansee(td, p) != 0) {
-				PROC_UNLOCK(p);
-				continue;
-			}
-			error = kern_procctl_single(td, p, com, data);
-			PROC_UNLOCK(p);
-			if (error == 0)
-				ok = 1;
-			else if (first_error == 0)
-				first_error = error;
-		}
-		if (ok)
-			error = 0;
-		else if (first_error != 0)
-			error = first_error;
-		else
-			/*
-			 * Was not able to see any processes in the
-			 * process group.
-			 */
-			error = ESRCH;
-		break;
-	default:
-		error = EINVAL;
-		break;
-	}
-	sx_sunlock(&proctree_lock);
-	return (error);
-}

Modified: stable/10/sys/sys/proc.h
==============================================================================
--- stable/10/sys/sys/proc.h	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/sys/proc.h	Mon Jan  5 03:27:09 2015	(r276686)
@@ -592,6 +592,14 @@ struct proc {
 	LIST_ENTRY(proc) p_orphan;	/* (e) List of orphan processes. */
 	LIST_HEAD(, proc) p_orphans;	/* (e) Pointer to list of orphans. */
 	u_int		p_treeflag;	/* (e) P_TREE flags */
+	struct proc	*p_reaper;	/* (e) My reaper. */
+	LIST_HEAD(, proc) p_reaplist;	/* (e) List of my descendants
+					       (if I am reaper). */
+	LIST_ENTRY(proc) p_reapsibling;	/* (e) List of siblings - descendants of
+					       the same reaper. */
+	pid_t		p_reapsubtree;	/* (e) Pid of the direct child of the
+					       reaper which spawned
+					       our subtree. */
 };
 
 #define	p_session	p_pgrp->pg_session
@@ -648,6 +656,7 @@ struct proc {
 #define	P_TREE_ORPHANED		0x00000001	/* Reparented, on orphan list */
 #define	P_TREE_FIRST_ORPHAN	0x00000002	/* First element of orphan
 						   list */
+#define	P_TREE_REAPER		0x00000004	/* Reaper of subtree */
 
 /*
  * These were process status values (p_stat), now they are only used in
@@ -897,6 +906,7 @@ void	proc_reparent(struct proc *child, s
 struct	pstats *pstats_alloc(void);
 void	pstats_fork(struct pstats *src, struct pstats *dst);
 void	pstats_free(struct pstats *ps);
+void	reaper_abandon_children(struct proc *p, bool exiting);
 int	securelevel_ge(struct ucred *cr, int level);
 int	securelevel_gt(struct ucred *cr, int level);
 void	sess_hold(struct session *);

Modified: stable/10/sys/sys/procctl.h
==============================================================================
--- stable/10/sys/sys/procctl.h	Mon Jan  5 02:06:26 2015	(r276685)
+++ stable/10/sys/sys/procctl.h	Mon Jan  5 03:27:09 2015	(r276686)
@@ -30,7 +30,17 @@
 #ifndef	_SYS_PROCCTL_H_
 #define	_SYS_PROCCTL_H_
 
+#ifndef _KERNEL
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif
+
 #define	PROC_SPROTECT		1	/* set protected state */
+#define	PROC_REAP_ACQUIRE	2	/* reaping enable */
+#define	PROC_REAP_RELEASE	3	/* reaping disable */
+#define	PROC_REAP_STATUS	4	/* reaping status */
+#define	PROC_REAP_GETPIDS	5	/* get descendants */
+#define	PROC_REAP_KILL		6	/* kill descendants */
 
 /* Operations for PROC_SPROTECT (passed in integer arg). */
 #define	PPROT_OP(x)	((x) & 0xf)
@@ -42,10 +52,51 @@
 #define	PPROT_DESCEND	0x10
 #define	PPROT_INHERIT	0x20
 
-#ifndef _KERNEL
-#include <sys/types.h>
-#include <sys/wait.h>
+/* Result of PREAP_STATUS (returned by value). */
+struct procctl_reaper_status {
+	u_int	rs_flags;
+	u_int	rs_children;
+	u_int	rs_descendants;
+	pid_t	rs_reaper;
+	pid_t	rs_pid;
+	u_int	rs_pad0[15];
+};
+
+/* struct procctl_reaper_status rs_flags */
+#define	REAPER_STATUS_OWNED	0x00000001
+#define	REAPER_STATUS_REALINIT	0x00000002
+
+struct procctl_reaper_pidinfo {
+	pid_t	pi_pid;
+	pid_t	pi_subtree;
+	u_int	pi_flags;
+	u_int	pi_pad0[15];
+};
+
+#define	REAPER_PIDINFO_VALID	0x00000001
+#define	REAPER_PIDINFO_CHILD	0x00000002
+
+struct procctl_reaper_pids {
+	u_int	rp_count;
+	u_int	rp_pad0[15];
+	struct procctl_reaper_pidinfo *rp_pids;
+};
+
+struct procctl_reaper_kill {
+	int	rk_sig;		/* in  - signal to send */
+	u_int	rk_flags;	/* in  - REAPER_KILL flags */
+	pid_t	rk_subtree;	/* in  - subtree, if REAPER_KILL_SUBTREE */
+	u_int	rk_killed;	/* out - count of processes sucessfully
+				   killed */
+	pid_t	rk_fpid;	/* out - first failed pid for which error
+				   is returned */
+	u_int	rk_pad0[15];
+};
 
+#define	REAPER_KILL_CHILDREN	0x00000001
+#define	REAPER_KILL_SUBTREE	0x00000002
+
+#ifndef _KERNEL
 __BEGIN_DECLS
 int	procctl(idtype_t, id_t, int, void *);
 __END_DECLS



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201501050327.t053RAhp037781>