Author: trociny
Date: Sun Apr 14 20:01:36 2013
New Revision: 249487
URL: http://svnweb.freebsd.org/changeset/base/249487

Log:
  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
  MFC after:    3 weeks

Modified:
  head/sys/kern/kern_descrip.c
  head/sys/kern/kern_proc.c
  head/sys/sys/user.h

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c        Sun Apr 14 19:59:38 2013        
(r249486)
+++ head/sys/kern/kern_descrip.c        Sun Apr 14 20:01:36 2013        
(r249487)
@@ -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>
@@ -3168,9 +3169,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, cap_rights_t fd_cap_rights, struct kinfo_file *kif,
-    struct sysctl_req *req)
+    struct sbuf *sb, ssize_t *remainder)
 {
        struct {
                int     fflag;
@@ -3197,6 +3198,8 @@ export_fd_for_sysctl(void *data, int typ
        int error;
        unsigned int i;
 
+       if (*remainder == 0)
+               return (0);
        bzero(kif, sizeof(*kif));
        switch (type) {
        case KF_TYPE_FIFO:
@@ -3241,32 +3244,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 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)
@@ -3286,14 +3297,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, kif, req);
+               export_fd_to_sb(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE,
+                   FREAD | FWRITE, -1, -1, 0, kif, sb, &remainder);
        if (textvp != NULL)
-               export_fd_for_sysctl(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT,
-                   FREAD, -1, -1, 0, kif, req);
+               export_fd_to_sb(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT,
+                   FREAD, -1, -1, 0, kif, sb, &remainder);
        if (cttyvp != NULL)
-               export_fd_for_sysctl(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY,
-                   FREAD | FWRITE, -1, -1, 0, kif, req);
+               export_fd_to_sb(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY,
+                   FREAD | FWRITE, -1, -1, 0, kif, sb, &remainder);
+       error = 0;
        if (fdp == NULL)
                goto fail;
        FILEDESC_SLOCK(fdp);
@@ -3302,8 +3314,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, kif, req);
+               export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD,
+                   FREAD, -1, -1, 0, kif, sb, &remainder);
                FILEDESC_SLOCK(fdp);
        }
        /* root directory */
@@ -3311,8 +3323,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, kif, req);
+               export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT,
+                   FREAD, -1, -1, 0, kif, sb, &remainder);
                FILEDESC_SLOCK(fdp);
        }
        /* jail directory */
@@ -3320,8 +3332,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, kif, req);
+               export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL,
+                   FREAD, -1, -1, 0, kif, sb, &remainder);
                FILEDESC_SLOCK(fdp);
        }
        for (i = 0; i < fdp->fd_nfiles; i++) {
@@ -3403,26 +3415,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_cap_rights, kif, req);
+               error = export_fd_to_sb(data, type, i, fflags, refcnt,
+                   offset, 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:
@@ -3432,6 +3432,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: head/sys/kern/kern_proc.c
==============================================================================
--- head/sys/kern/kern_proc.c   Sun Apr 14 19:59:38 2013        (r249486)
+++ head/sys/kern/kern_proc.c   Sun Apr 14 20:01:36 2013        (r249487)
@@ -1089,9 +1089,6 @@ zpfind(pid_t pid)
        return (p);
 }
 
-#define KERN_PROC_ZOMBMASK     0x3
-#define KERN_PROC_NOTHREADS    0x4
-
 #ifdef COMPAT_FREEBSD32
 
 /*
@@ -1191,59 +1188,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)
@@ -1277,6 +1284,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);
@@ -1286,7 +1297,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);
        }
 
@@ -1415,7 +1426,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);
@@ -2119,8 +2130,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;
@@ -2128,16 +2142,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);
@@ -2145,6 +2158,7 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_AR
        }
        kve = malloc(sizeof(*kve), M_TEMP, M_WAITOK);
 
+       error = 0;
        map = &vm->vm_map;
        vm_map_lock_read(map);
        for (entry = map->header.next; entry != &map->header;
@@ -2284,7 +2298,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;
@@ -2300,6 +2314,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: head/sys/sys/user.h
==============================================================================
--- head/sys/sys/user.h Sun Apr 14 19:59:38 2013        (r249486)
+++ head/sys/sys/user.h Sun Apr 14 20:01:36 2013        (r249487)
@@ -491,6 +491,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 */
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to