summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortrociny <trociny@FreeBSD.org>2013-04-14 20:01:36 +0000
committertrociny <trociny@FreeBSD.org>2013-04-14 20:01:36 +0000
commit335f3dbd9136ccf61c363fee13dc4a90c89cce50 (patch)
treeb5d51cb05a61768573b30bd3294f22134dbe82de /sys/kern
parent99603a0f212eda46b1b439585792e59c69eba194 (diff)
downloadFreeBSD-src-335f3dbd9136ccf61c363fee13dc4a90c89cce50.zip
FreeBSD-src-335f3dbd9136ccf61c363fee13dc4a90c89cce50.tar.gz
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
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_descrip.c108
-rw-r--r--sys/kern/kern_proc.c138
2 files changed, 154 insertions, 92 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index c765ee2..a9795ca 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -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) == KINFO_FILE_SIZE);
#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 type, int fd, int fflags, int refcnt,
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 type, int fd, int fflags, int refcnt,
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_ARGS)
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_ARGS)
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_ARGS)
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_ARGS)
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_ARGS)
* 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)
{
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index e3f3211..ded8950 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -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 kinfo_proc *ki, struct kinfo_proc32 *ki32)
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_ARGS)
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_ARGS)
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_ARGS)
}
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_ARGS)
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_ARGS)
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)
OpenPOWER on IntegriCloud