Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Feb 2018 15:16:58 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329985 - head/sys/kern
Message-ID:  <201802251516.w1PFGw7K060391@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Sun Feb 25 15:16:58 2018
New Revision: 329985
URL: https://svnweb.freebsd.org/changeset/base/329985

Log:
  Don't generate data in sysctl_out_proc unless we intend to copy out.
  
  The first call is used to gauge how much spaces is needed. Just computing
  the size instead of generating the output allows to not take the proctree
  lock.

Modified:
  head/sys/kern/kern_proc.c

Modified: head/sys/kern/kern_proc.c
==============================================================================
--- head/sys/kern/kern_proc.c	Sun Feb 25 14:29:43 2018	(r329984)
+++ head/sys/kern/kern_proc.c	Sun Feb 25 15:16:58 2018	(r329985)
@@ -1347,6 +1347,32 @@ freebsd32_kinfo_proc_out(const struct kinfo_proc *ki, 
 }
 #endif
 
+static ssize_t
+kern_proc_out_size(struct proc *p, int flags)
+{
+	ssize_t size = 0;
+
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+
+	if ((flags & KERN_PROC_NOTHREADS) != 0) {
+#ifdef COMPAT_FREEBSD32
+		if ((flags & KERN_PROC_MASK32) != 0) {
+			size += sizeof(struct kinfo_proc32);
+		} else
+#endif
+			size += sizeof(struct kinfo_proc);
+	} else {
+#ifdef COMPAT_FREEBSD32
+		if ((flags & KERN_PROC_MASK32) != 0)
+			size += sizeof(struct kinfo_proc32) * p->p_numthreads;
+		else
+#endif
+			size += sizeof(struct kinfo_proc) * p->p_numthreads;
+	}
+	PROC_UNLOCK(p);
+	return (size);
+}
+
 int
 kern_proc_out(struct proc *p, struct sbuf *sb, int flags)
 {
@@ -1399,6 +1425,9 @@ sysctl_out_proc(struct proc *p, struct sysctl_req *req
 	struct kinfo_proc ki;
 	int error, error2;
 
+	if (req->oldptr == NULL)
+		return (SYSCTL_OUT(req, 0, kern_proc_out_size(p, flags)));
+
 	sbuf_new_for_sysctl(&sb, (char *)&ki, sizeof(ki), req);
 	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
 	error = kern_proc_out(p, &sb, flags);
@@ -1461,16 +1490,22 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 		break;
 	}
 
-	if (!req->oldptr) {
+	if (req->oldptr == NULL) {
 		/* overestimate by 5 procs */
 		error = SYSCTL_OUT(req, 0, sizeof (struct kinfo_proc) * 5);
 		if (error)
 			return (error);
+	} else {
+		error = sysctl_wire_old_buffer(req, 0);
+		if (error != 0)
+			return (error);
+		/*
+		 * This lock is only needed to safely grab the parent of a
+		 * traced process. Only grab it if we are producing any
+		 * data to begin with.
+		 */
+		sx_slock(&proctree_lock);
 	}
-	error = sysctl_wire_old_buffer(req, 0);
-	if (error != 0)
-		return (error);
-	sx_slock(&proctree_lock);
 	sx_slock(&allproc_lock);
 	for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) {
 		if (!doingzomb)
@@ -1571,16 +1606,15 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 			}
 
 			error = sysctl_out_proc(p, req, flags);
-			if (error) {
-				sx_sunlock(&allproc_lock);
-				sx_sunlock(&proctree_lock);
-				return (error);
-			}
+			if (error)
+				goto out;
 		}
 	}
+out:
 	sx_sunlock(&allproc_lock);
-	sx_sunlock(&proctree_lock);
-	return (0);
+	if (req->oldptr != NULL)
+		sx_sunlock(&proctree_lock);
+	return (error);
 }
 
 struct pargs *



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