svn commit: r250376 - in stable/9/sys: kern sys

Mikolaj Golub trociny at FreeBSD.org
Wed May 8 18:39:13 UTC 2013


Author: trociny
Date: Wed May  8 18:39:12 2013
New Revision: 250376
URL: http://svnweb.freebsd.org/changeset/base/250376

Log:
  MFC r249487:
  
  Re-factor the code to provide kern_proc_filedesc_out(), kern_proc_out(),
  and kern_proc_vmmap_out() functions to output process kinfo structures
  to sbuf, to make the code reusable.
  
  The functions are going to be used in the coredump routine to store
  procstat info in the core program header notes.
  
  Reviewed by:	kib

Modified:
  stable/9/sys/kern/kern_descrip.c
  stable/9/sys/kern/kern_proc.c
  stable/9/sys/sys/user.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/sys/   (props changed)

Modified: stable/9/sys/kern/kern_descrip.c
==============================================================================
--- stable/9/sys/kern/kern_descrip.c	Wed May  8 18:25:46 2013	(r250375)
+++ stable/9/sys/kern/kern_descrip.c	Wed May  8 18:39:12 2013	(r250376)
@@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/protosw.h>
 #include <sys/racct.h>
 #include <sys/resourcevar.h>
+#include <sys/sbuf.h>
 #include <sys/signalvar.h>
 #include <sys/socketvar.h>
 #include <sys/stat.h>
@@ -3226,9 +3227,9 @@ CTASSERT(sizeof(struct kinfo_file) == KI
 #endif
 
 static int
-export_fd_for_sysctl(void *data, int type, int fd, int fflags, int refcnt,
+export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt,
     int64_t offset, int fd_is_cap, cap_rights_t fd_cap_rights,
-    struct kinfo_file *kif, struct sysctl_req *req)
+    struct kinfo_file *kif, struct sbuf *sb, ssize_t *remainder)
 {
 	struct {
 		int	fflag;
@@ -3255,6 +3256,8 @@ export_fd_for_sysctl(void *data, int typ
 	int error, vfslocked;
 	unsigned int i;
 
+	if (*remainder == 0)
+		return (0);
 	bzero(kif, sizeof(*kif));
 	switch (type) {
 	case KF_TYPE_FIFO:
@@ -3304,32 +3307,40 @@ export_fd_for_sysctl(void *data, int typ
 	kif->kf_structsize = offsetof(struct kinfo_file, kf_path) +
 	    strlen(kif->kf_path) + 1;
 	kif->kf_structsize = roundup(kif->kf_structsize, sizeof(uint64_t));
-	error = SYSCTL_OUT(req, kif, kif->kf_structsize);
+	if (*remainder != -1) {
+		if (*remainder < kif->kf_structsize) {
+			/* Terminate export. */
+			*remainder = 0;
+			return (0);
+		}
+		*remainder -= kif->kf_structsize;
+	}
+	error = sbuf_bcat(sb, kif, kif->kf_structsize);
 	return (error);
 }
 
 /*
- * Get per-process file descriptors for use by procstat(1), et al.
+ * Store a process file descriptor information to sbuf.
+ *
+ * Takes a locked proc as argument, and returns with the proc unlocked.
  */
-static int
-sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
+int
+kern_proc_filedesc_out(struct proc *p,  struct sbuf *sb, ssize_t maxlen)
 {
 	struct file *fp;
 	struct filedesc *fdp;
 	struct kinfo_file *kif;
-	struct proc *p;
 	struct vnode *cttyvp, *textvp, *tracevp;
-	size_t oldidx;
 	int64_t offset;
 	void *data;
-	int error, i, *name;
+	ssize_t remainder;
+	int error, i;
 	int fd_is_cap, type, refcnt, fflags;
 	cap_rights_t fd_cap_rights;
 
-	name = (int *)arg1;
-	error = pget((pid_t)name[0], PGET_CANDEBUG, &p);
-	if (error != 0)
-		return (error);
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+
+	remainder = maxlen;
 	/* ktrace vnode */
 	tracevp = p->p_tracevp;
 	if (tracevp != NULL)
@@ -3349,14 +3360,15 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER
 	PROC_UNLOCK(p);
 	kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK);
 	if (tracevp != NULL)
-		export_fd_for_sysctl(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE,
-		    FREAD | FWRITE, -1, -1, 0, 0, kif, req);
+		export_fd_to_sb(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE,
+		    FREAD | FWRITE, -1, -1, 0, 0, kif, sb, &remainder);
 	if (textvp != NULL)
-		export_fd_for_sysctl(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT,
-		    FREAD, -1, -1, 0, 0, kif, req);
+		export_fd_to_sb(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT,
+		    FREAD, -1, -1, 0, 0, kif, sb, &remainder);
 	if (cttyvp != NULL)
-		export_fd_for_sysctl(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY,
-		    FREAD | FWRITE, -1, -1, 0, 0, kif, req);
+		export_fd_to_sb(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY,
+		    FREAD | FWRITE, -1, -1, 0, 0, kif, sb, &remainder);
+	error = 0;
 	if (fdp == NULL)
 		goto fail;
 	FILEDESC_SLOCK(fdp);
@@ -3365,8 +3377,8 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER
 		vref(fdp->fd_cdir);
 		data = fdp->fd_cdir;
 		FILEDESC_SUNLOCK(fdp);
-		export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD,
-		    FREAD, -1, -1, 0, 0, kif, req);
+		export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD,
+		    FREAD, -1, -1, 0, 0, kif, sb, &remainder);
 		FILEDESC_SLOCK(fdp);
 	}
 	/* root directory */
@@ -3374,8 +3386,8 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER
 		vref(fdp->fd_rdir);
 		data = fdp->fd_rdir;
 		FILEDESC_SUNLOCK(fdp);
-		export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT,
-		    FREAD, -1, -1, 0, 0, kif, req);
+		export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT,
+		    FREAD, -1, -1, 0, 0, kif, sb, &remainder);
 		FILEDESC_SLOCK(fdp);
 	}
 	/* jail directory */
@@ -3383,8 +3395,8 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER
 		vref(fdp->fd_jdir);
 		data = fdp->fd_jdir;
 		FILEDESC_SUNLOCK(fdp);
-		export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL,
-		    FREAD, -1, -1, 0, 0, kif, req);
+		export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL,
+		    FREAD, -1, -1, 0, 0, kif, sb, &remainder);
 		FILEDESC_SLOCK(fdp);
 	}
 	for (i = 0; i < fdp->fd_nfiles; i++) {
@@ -3479,26 +3491,14 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER
 		 * re-validate and re-evaluate its properties when
 		 * the loop continues.
 		 */
-		oldidx = req->oldidx;
 		if (type == KF_TYPE_VNODE || type == KF_TYPE_FIFO)
 			FILEDESC_SUNLOCK(fdp);
-		error = export_fd_for_sysctl(data, type, i, fflags, refcnt,
-		    offset, fd_is_cap, fd_cap_rights, kif, req);
+		error = export_fd_to_sb(data, type, i, fflags, refcnt,
+		    offset, fd_is_cap, fd_cap_rights, kif, sb, &remainder);
 		if (type == KF_TYPE_VNODE || type == KF_TYPE_FIFO)
 			FILEDESC_SLOCK(fdp);
-		if (error) {
-			if (error == ENOMEM) {
-				/*
-				 * The hack to keep the ABI of sysctl
-				 * kern.proc.filedesc intact, but not
-				 * to account a partially copied
-				 * kinfo_file into the oldidx.
-				 */
-				req->oldidx = oldidx;
-				error = 0;
-			}
+		if (error)
 			break;
-		}
 	}
 	FILEDESC_SUNLOCK(fdp);
 fail:
@@ -3508,6 +3508,34 @@ fail:
 	return (error);
 }
 
+#define FILEDESC_SBUF_SIZE	(sizeof(struct kinfo_file) * 5)
+
+/*
+ * Get per-process file descriptors for use by procstat(1), et al.
+ */
+static int
+sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
+{
+	struct sbuf sb;
+	struct proc *p;
+	ssize_t maxlen;
+	int error, error2, *name;
+
+	name = (int *)arg1;
+
+	sbuf_new_for_sysctl(&sb, NULL, FILEDESC_SBUF_SIZE, req);
+	error = pget((pid_t)name[0], PGET_CANDEBUG, &p);
+	if (error != 0) {
+		sbuf_delete(&sb);
+		return (error);
+	}
+	maxlen = req->oldptr != NULL ? req->oldlen : -1;
+	error = kern_proc_filedesc_out(p, &sb, maxlen);
+	error2 = sbuf_finish(&sb);
+	sbuf_delete(&sb);
+	return (error != 0 ? error : error2);
+}
+
 int
 vntype_to_kinfo(int vtype)
 {

Modified: stable/9/sys/kern/kern_proc.c
==============================================================================
--- stable/9/sys/kern/kern_proc.c	Wed May  8 18:25:46 2013	(r250375)
+++ stable/9/sys/kern/kern_proc.c	Wed May  8 18:39:12 2013	(r250376)
@@ -1090,9 +1090,6 @@ zpfind(pid_t pid)
 	return (p);
 }
 
-#define KERN_PROC_ZOMBMASK	0x3
-#define KERN_PROC_NOTHREADS	0x4
-
 #ifdef COMPAT_FREEBSD32
 
 /*
@@ -1192,59 +1189,69 @@ freebsd32_kinfo_proc_out(const struct ki
 	CP(*ki, *ki32, ki_sflag);
 	CP(*ki, *ki32, ki_tdflags);
 }
-
-static int
-sysctl_out_proc_copyout(struct kinfo_proc *ki, struct sysctl_req *req)
-{
-	struct kinfo_proc32 ki32;
-	int error;
-
-	if (req->flags & SCTL_MASK32) {
-		freebsd32_kinfo_proc_out(ki, &ki32);
-		error = SYSCTL_OUT(req, &ki32, sizeof(struct kinfo_proc32));
-	} else
-		error = SYSCTL_OUT(req, ki, sizeof(struct kinfo_proc));
-	return (error);
-}
-#else
-static int
-sysctl_out_proc_copyout(struct kinfo_proc *ki, struct sysctl_req *req)
-{
-
-	return (SYSCTL_OUT(req, ki, sizeof(struct kinfo_proc)));
-}
 #endif
 
-/*
- * Must be called with the process locked and will return with it unlocked.
- */
-static int
-sysctl_out_proc(struct proc *p, struct sysctl_req *req, int flags)
+int
+kern_proc_out(struct proc *p, struct sbuf *sb, int flags)
 {
 	struct thread *td;
-	struct kinfo_proc kinfo_proc;
-	int error = 0;
-	struct proc *np;
-	pid_t pid = p->p_pid;
+	struct kinfo_proc ki;
+#ifdef COMPAT_FREEBSD32
+	struct kinfo_proc32 ki32;
+#endif
+	int error;
 
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	MPASS(FIRST_THREAD_IN_PROC(p) != NULL);
 
-	fill_kinfo_proc(p, &kinfo_proc);
-	if (flags & KERN_PROC_NOTHREADS)
-		error = sysctl_out_proc_copyout(&kinfo_proc, req);
-	else {
+	error = 0;
+	fill_kinfo_proc(p, &ki);
+	if ((flags & KERN_PROC_NOTHREADS) != 0) {
+#ifdef COMPAT_FREEBSD32
+		if ((flags & KERN_PROC_MASK32) != 0) {
+			freebsd32_kinfo_proc_out(&ki, &ki32);
+			error = sbuf_bcat(sb, &ki32, sizeof(ki32));
+		} else
+#endif
+			error = sbuf_bcat(sb, &ki, sizeof(ki));
+	} else {
 		FOREACH_THREAD_IN_PROC(p, td) {
-			fill_kinfo_thread(td, &kinfo_proc, 1);
-			error = sysctl_out_proc_copyout(&kinfo_proc, req);
+			fill_kinfo_thread(td, &ki, 1);
+#ifdef COMPAT_FREEBSD32
+			if ((flags & KERN_PROC_MASK32) != 0) {
+				freebsd32_kinfo_proc_out(&ki, &ki32);
+				error = sbuf_bcat(sb, &ki32, sizeof(ki32));
+			} else
+#endif
+				error = sbuf_bcat(sb, &ki, sizeof(ki));
 			if (error)
 				break;
 		}
 	}
 	PROC_UNLOCK(p);
-	if (error)
+	return (error);
+}
+
+static int
+sysctl_out_proc(struct proc *p, struct sysctl_req *req, int flags,
+    int doingzomb)
+{
+	struct sbuf sb;
+	struct kinfo_proc ki;
+	struct proc *np;
+	int error, error2;
+	pid_t pid;
+
+	pid = p->p_pid;
+	sbuf_new_for_sysctl(&sb, (char *)&ki, sizeof(ki), req);
+	error = kern_proc_out(p, &sb, flags);
+	error2 = sbuf_finish(&sb);
+	sbuf_delete(&sb);
+	if (error != 0)
 		return (error);
-	if (flags & KERN_PROC_ZOMBMASK)
+	else if (error2 != 0)
+		return (error2);
+	if (doingzomb)
 		np = zpfind(pid);
 	else {
 		if (pid == 0)
@@ -1278,6 +1285,10 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 		flags = 0;
 		oid_number &= ~KERN_PROC_INC_THREAD;
 	}
+#ifdef COMPAT_FREEBSD32
+	if (req->flags & SCTL_MASK32)
+		flags |= KERN_PROC_MASK32;
+#endif
 	if (oid_number == KERN_PROC_PID) {
 		if (namelen != 1)
 			return (EINVAL);
@@ -1287,7 +1298,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 		error = pget((pid_t)name[0], PGET_CANSEE, &p);
 		if (error != 0)
 			return (error);
-		error = sysctl_out_proc(p, req, flags);
+		error = sysctl_out_proc(p, req, flags, 0);
 		return (error);
 	}
 
@@ -1416,7 +1427,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 
 			}
 
-			error = sysctl_out_proc(p, req, flags | doingzomb);
+			error = sysctl_out_proc(p, req, flags, doingzomb);
 			if (error) {
 				sx_sunlock(&allproc_lock);
 				return (error);
@@ -2125,8 +2136,11 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_A
 CTASSERT(sizeof(struct kinfo_vmentry) == KINFO_VMENTRY_SIZE);
 #endif
 
-static int
-sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
+/*
+ * Must be called with the process locked and will return unlocked.
+ */
+int
+kern_proc_vmmap_out(struct proc *p, struct sbuf *sb)
 {
 	vm_map_entry_t entry, tmp_entry;
 	unsigned int last_timestamp;
@@ -2134,16 +2148,15 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_AR
 	struct kinfo_vmentry *kve;
 	struct vattr va;
 	struct ucred *cred;
-	int error, *name;
+	int error;
 	struct vnode *vp;
-	struct proc *p;
 	struct vmspace *vm;
 	vm_map_t map;
 
-	name = (int *)arg1;
-	error = pget((pid_t)name[0], PGET_WANTREAD, &p);
-	if (error != 0)
-		return (error);
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+
+	_PHOLD(p);
+	PROC_UNLOCK(p);
 	vm = vmspace_acquire_ref(p);
 	if (vm == NULL) {
 		PRELE(p);
@@ -2151,6 +2164,7 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_AR
 	}
 	kve = malloc(sizeof(*kve), M_TEMP, M_WAITOK);
 
+	error = 0;
 	map = &vm->vm_map;	/* XXXRW: More locking required? */
 	vm_map_lock_read(map);
 	for (entry = map->header.next; entry != &map->header;
@@ -2292,7 +2306,7 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_AR
 		    strlen(kve->kve_path) + 1;
 		kve->kve_structsize = roundup(kve->kve_structsize,
 		    sizeof(uint64_t));
-		error = SYSCTL_OUT(req, kve, kve->kve_structsize);
+		error = sbuf_bcat(sb, kve, kve->kve_structsize);
 		vm_map_lock_read(map);
 		if (error)
 			break;
@@ -2308,6 +2322,26 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_AR
 	return (error);
 }
 
+static int
+sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
+{
+	struct proc *p;
+	struct sbuf sb;
+	int error, error2, *name;
+
+	name = (int *)arg1;
+	sbuf_new_for_sysctl(&sb, NULL, sizeof(struct kinfo_vmentry), req);
+	error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p);
+	if (error != 0) {
+		sbuf_delete(&sb);
+		return (error);
+	}
+	error = kern_proc_vmmap_out(p, &sb);
+	error2 = sbuf_finish(&sb);
+	sbuf_delete(&sb);
+	return (error != 0 ? error : error2);
+}
+
 #if defined(STACK) || defined(DDB)
 static int
 sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS)

Modified: stable/9/sys/sys/user.h
==============================================================================
--- stable/9/sys/sys/user.h	Wed May  8 18:25:46 2013	(r250375)
+++ stable/9/sys/sys/user.h	Wed May  8 18:39:12 2013	(r250376)
@@ -493,6 +493,25 @@ struct kinfo_kstack {
 };
 
 #ifdef _KERNEL
+/* Flags for kern_proc_out function. */
+#define KERN_PROC_NOTHREADS	0x1
+#define KERN_PROC_MASK32	0x2
+
+struct sbuf;
+
+/*
+ * The kern_proc out functions are helper functions to dump process
+ * miscellaneous kinfo structures to sbuf.  The main consumers are KERN_PROC
+ * sysctls but they may also be used by other kernel subsystems.
+ *
+ * The functions manipulate the process locking state and expect the process
+ * to be locked on enter.  On return the process is unlocked.
+ */
+
+int	kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen);
+int	kern_proc_out(struct proc *p, struct sbuf *sb, int flags);
+int	kern_proc_vmmap_out(struct proc *p, struct sbuf *sb);
+
 int	vntype_to_kinfo(int vtype);
 #endif /* !_KERNEL */
 


More information about the svn-src-all mailing list