summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authoragc <agc@NetBSD.org>2007-05-24 00:37:40 +0000
committeragc <agc@NetBSD.org>2007-05-24 00:37:40 +0000
commit4dbe5ed7e761dc649d5ed976ae217050e22cfcdc (patch)
tree6b4e735bdd365f09e5149e832f3e7f3afe938449 /sys
parent94b0103837aad4ca66af65b37e23c61ec987398d (diff)
Extend the Linux emulation of /proc to include
/proc/stat /proc/loadavg and /proc/<pid>/statm. These are only present when -o linux is specified as a mount option to procfs. Factor out some common code so that it can be used by a number of functions. XXX The values returned in the statm emulation need to be verified.
Diffstat (limited to 'sys')
-rw-r--r--sys/miscfs/procfs/procfs.h11
-rw-r--r--sys/miscfs/procfs/procfs_linux.c223
-rw-r--r--sys/miscfs/procfs/procfs_subr.c19
-rw-r--r--sys/miscfs/procfs/procfs_vnops.c13
4 files changed, 224 insertions, 42 deletions
diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h
index f8997551fc6..dcd4bb2c1ef 100644
--- a/sys/miscfs/procfs/procfs.h
+++ b/sys/miscfs/procfs/procfs.h
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs.h,v 1.63 2007/02/09 21:55:36 ad Exp $ */
+/* $NetBSD: procfs.h,v 1.64 2007/05/24 00:37:40 agc Exp $ */
/*
* Copyright (c) 1993
@@ -105,6 +105,9 @@ typedef enum {
PFSchroot, /* the process's current root directory */
PFSemul, /* the process's emulation */
PFSdevices, /* major/device name mappings (if -o linux) */
+ PFScpustat, /* status info (if -o linux) */
+ PFSloadavg, /* load average (if -o linux) */
+ PFSstatm, /* process memory info (if -o linux) */
#ifdef __HAVE_PROCFS_MACHDEP
PROCFS_MACHDEP_NODE_TYPES
#endif
@@ -208,6 +211,12 @@ int procfs_dodevices(struct lwp *, struct proc *, struct pfsnode *,
struct uio *);
int procfs_docpuinfo(struct lwp *, struct proc *, struct pfsnode *,
struct uio *);
+int procfs_docpustat(struct lwp *, struct proc *, struct pfsnode *,
+ struct uio *);
+int procfs_doloadavg(struct lwp *, struct proc *, struct pfsnode *,
+ struct uio *);
+int procfs_do_pid_statm(struct lwp *, struct lwp *, struct pfsnode *,
+ struct uio *);
int procfs_dofd(struct lwp *, struct proc *, struct pfsnode *,
struct uio *);
int procfs_douptime(struct lwp *, struct proc *, struct pfsnode *,
diff --git a/sys/miscfs/procfs/procfs_linux.c b/sys/miscfs/procfs/procfs_linux.c
index 39cef335746..ff7cb5f9596 100644
--- a/sys/miscfs/procfs/procfs_linux.c
+++ b/sys/miscfs/procfs/procfs_linux.c
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs_linux.c,v 1.34 2007/04/01 03:16:44 christos Exp $ */
+/* $NetBSD: procfs_linux.c,v 1.35 2007/05/24 00:37:40 agc Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_linux.c,v 1.34 2007/04/01 03:16:44 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_linux.c,v 1.35 2007/05/24 00:37:40 agc Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -68,6 +68,52 @@ extern int max_devsw_convs;
#define LBFSZ (8 * 1024)
+static void
+get_proc_size_info(struct lwp *l, unsigned long *stext, unsigned long *etext, unsigned long *sstack)
+{
+ struct proc *p = l->l_proc;
+ struct vmspace *vm;
+ struct vm_map *map;
+ struct vm_map_entry *entry;
+
+ *stext = 0;
+ *etext = 0;
+ *sstack = 0;
+
+ proc_vmspace_getref(p, &vm);
+ map = &vm->vm_map;
+ vm_map_lock_read(map);
+
+ for (entry = map->header.next; entry != &map->header;
+ entry = entry->next) {
+ if (UVM_ET_ISSUBMAP(entry))
+ continue;
+ /* assume text is the first entry */
+ if (*stext == *etext) {
+ *stext = entry->start;
+ *etext = entry->end;
+ break;
+ }
+ }
+#ifdef LINUX_USRSTACK
+ if (strcmp(p->p_emul->e_name, "linux") == 0 &&
+ LINUX_USRSTACK < USRSTACK)
+ *sstack = (unsigned long) LINUX_USRSTACK;
+ else
+#endif
+ *sstack = (unsigned long) USRSTACK;
+
+ /*
+ * jdk 1.6 compares low <= addr && addr < high
+ * if we put addr == high, then the test fails
+ * so eat one page.
+ */
+ *sstack -= PAGE_SIZE;
+
+ vm_map_unlock_read(map);
+ uvmspace_free(vm);
+}
+
/*
* Linux compatible /proc/meminfo. Only active when the -o linux
* mountflag is used.
@@ -172,6 +218,143 @@ out:
}
/*
+ * Linux compatible /proc/stat. Only active when the -o linux
+ * mountflag is used.
+ */
+int
+procfs_docpustat(struct lwp *curl, struct proc *p,
+ struct pfsnode *pfs, struct uio *uio)
+{
+ struct timeval runtime;
+ struct cpu_info *ci;
+ CPU_INFO_ITERATOR cii;
+ char *bf;
+ int error;
+ int len;
+ int i;
+
+ error = ENAMETOOLONG;
+ bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
+
+ len = snprintf(bf, LBFSZ,
+ "cpu %llu %llu %llu %llu\n",
+ curcpu()->ci_schedstate.spc_cp_time[CP_USER],
+ curcpu()->ci_schedstate.spc_cp_time[CP_NICE],
+ curcpu()->ci_schedstate.spc_cp_time[CP_SYS] /*+ [CP_INTR]*/,
+ curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]);
+ if (len == 0)
+ goto out;
+
+ i = 0;
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ len += snprintf(&bf[len], LBFSZ - len,
+ "cpu%d %llu %llu %llu %llu\n", i,
+ ci->ci_schedstate.spc_cp_time[CP_USER],
+ ci->ci_schedstate.spc_cp_time[CP_NICE],
+ ci->ci_schedstate.spc_cp_time[CP_SYS],
+ ci->ci_schedstate.spc_cp_time[CP_IDLE]);
+ if (len >= LBFSZ)
+ goto out;
+ i += 1;
+ }
+
+ timersub(&curcpu()->ci_schedstate.spc_runtime, &boottime, &runtime);
+ len += snprintf(&bf[len], LBFSZ - len,
+ "disk 0 0 0 0\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u\n"
+ "ctxt %u\n"
+ "btime %lld\n",
+ uvmexp.pageins, uvmexp.pdpageouts,
+ uvmexp.pgswapin, uvmexp.pgswapout,
+ uvmexp.intrs,
+ uvmexp.swtch,
+ (long long)boottime.tv_sec);
+ if (len >= LBFSZ)
+ goto out;
+
+ error = uiomove_frombuf(bf, len, uio);
+out:
+ free(bf, M_TEMP);
+ return error;
+}
+
+/*
+ * Linux compatible /proc/loadavg. Only active when the -o linux
+ * mountflag is used.
+ */
+int
+procfs_doloadavg(struct lwp *curl, struct proc *p,
+ struct pfsnode *pfs, struct uio *uio)
+{
+ char *bf;
+ int error;
+ int len;
+
+ error = ENAMETOOLONG;
+ bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
+
+ averunnable.fscale = FSCALE;
+ len = snprintf(bf, LBFSZ,
+ "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
+ (int)(averunnable.ldavg[0] / averunnable.fscale),
+ (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
+ (int)(averunnable.ldavg[1] / averunnable.fscale),
+ (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
+ (int)(averunnable.ldavg[2] / averunnable.fscale),
+ (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
+ 1, /* number of ONPROC processes */
+ nprocs,
+ 30000); /* last pid */
+ if (len == 0)
+ goto out;
+
+ error = uiomove_frombuf(bf, len, uio);
+out:
+ free(bf, M_TEMP);
+ return error;
+}
+
+/*
+ * Linux compatible /proc/<pid>/statm. Only active when the -o linux
+ * mountflag is used.
+ */
+int
+procfs_do_pid_statm(struct lwp *curl, struct lwp *l,
+ struct pfsnode *pfs, struct uio *uio)
+{
+ unsigned long stext = 0, etext = 0, sstack = 0;
+ struct proc *p = l->l_proc;
+ struct rusage *ru = &p->p_stats->p_ru;
+ char *bf;
+ int error;
+ int len;
+
+ error = ENAMETOOLONG;
+ bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
+
+ get_proc_size_info(l, &stext, &etext, &sstack);
+
+ len = snprintf(bf, LBFSZ,
+ "%lu %lu %lu %lu %lu %lu %lu\n",
+ (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss), /* size */
+ ru->ru_maxrss, /* resident */
+ ru->ru_ixrss, /* shared */
+ stext,
+ etext,
+ sstack,
+ (unsigned long) 0);
+ if (len == 0)
+ goto out;
+
+ error = uiomove_frombuf(bf, len, uio);
+out:
+ free(bf, M_TEMP);
+ return error;
+}
+
+/*
* Linux compatible /proc/<pid>/stat. Only active when the -o linux
* mountflag is used.
*/
@@ -185,47 +368,13 @@ procfs_do_pid_stat(struct lwp *curl, struct lwp *l,
struct tty *tty = p->p_session->s_ttyp;
struct rusage *ru = &p->p_stats->p_ru;
struct rusage *cru = &p->p_stats->p_cru;
- struct vmspace *vm;
- struct vm_map *map;
- struct vm_map_entry *entry;
unsigned long stext = 0, etext = 0, sstack = 0;
struct timeval rt;
int error = 0;
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
- proc_vmspace_getref(p, &vm);
- map = &vm->vm_map;
- vm_map_lock_read(map);
-
- for (entry = map->header.next; entry != &map->header;
- entry = entry->next) {
- if (UVM_ET_ISSUBMAP(entry))
- continue;
- /* assume text is the first entry */
- if (stext == etext) {
- stext = entry->start;
- etext = entry->end;
- break;
- }
- }
-#ifdef LINUX_USRSTACK
- if (strcmp(p->p_emul->e_name, "linux") == 0 &&
- LINUX_USRSTACK < USRSTACK)
- sstack = (unsigned long) LINUX_USRSTACK;
- else
-#endif
- sstack = (unsigned long) USRSTACK;
-
- /*
- * jdk 1.6 compares low <= addr && addr < high
- * if we put addr == high, then the test fails
- * so eat one page.
- */
- sstack -= PAGE_SIZE;
-
- vm_map_unlock_read(map);
- uvmspace_free(vm);
+ get_proc_size_info(l, &stext, &etext, &sstack);
mutex_enter(&proclist_lock);
mutex_enter(&p->p_mutex);
diff --git a/sys/miscfs/procfs/procfs_subr.c b/sys/miscfs/procfs/procfs_subr.c
index 7a7633e4ce3..66378e0e974 100644
--- a/sys/miscfs/procfs/procfs_subr.c
+++ b/sys/miscfs/procfs/procfs_subr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs_subr.c,v 1.79 2007/03/09 14:11:23 ad Exp $ */
+/* $NetBSD: procfs_subr.c,v 1.80 2007/05/24 00:37:41 agc Exp $ */
/*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@@ -109,7 +109,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.79 2007/03/09 14:11:23 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.80 2007/05/24 00:37:41 agc Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -295,10 +295,13 @@ procfs_allocvp(mp, vpp, pid, pfs_type, fd, p)
case PFScmdline: /* /proc/N/cmdline = -r--r--r-- */
case PFSemul: /* /proc/N/emul = -r--r--r-- */
case PFSmeminfo: /* /proc/meminfo = -r--r--r-- */
+ case PFScpustat: /* /proc/stat = -r--r--r-- */
case PFSdevices: /* /proc/devices = -r--r--r-- */
case PFScpuinfo: /* /proc/cpuinfo = -r--r--r-- */
case PFSuptime: /* /proc/uptime = -r--r--r-- */
case PFSmounts: /* /proc/mounts = -r--r--r-- */
+ case PFSloadavg: /* /proc/loadavg = -r--r--r-- */
+ case PFSstatm: /* /proc/N/statm = -r--r--r-- */
pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
vp->v_type = VREG;
break;
@@ -436,6 +439,18 @@ procfs_rw(v)
error = procfs_docpuinfo(curl, p, pfs, uio);
break;
+ case PFScpustat:
+ error = procfs_docpustat(curl, p, pfs, uio);
+ break;
+
+ case PFSloadavg:
+ error = procfs_doloadavg(curl, p, pfs, uio);
+ break;
+
+ case PFSstatm:
+ error = procfs_do_pid_statm(curl, l, pfs, uio);
+ break;
+
case PFSfd:
error = procfs_dofd(curl, p, pfs, uio);
break;
diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c
index b2957533ef5..2aa3450b79b 100644
--- a/sys/miscfs/procfs/procfs_vnops.c
+++ b/sys/miscfs/procfs/procfs_vnops.c
@@ -1,4 +1,4 @@
-/* $NetBSD: procfs_vnops.c,v 1.156 2007/04/04 10:50:42 rmind Exp $ */
+/* $NetBSD: procfs_vnops.c,v 1.157 2007/05/24 00:37:41 agc Exp $ */
/*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@@ -112,7 +112,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.156 2007/04/04 10:50:42 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.157 2007/05/24 00:37:41 agc Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -181,6 +181,7 @@ static const struct proc_target {
{ DT_LNK, N("cwd"), PFScwd, NULL },
{ DT_LNK, N("root"), PFSchroot, NULL },
{ DT_LNK, N("emul"), PFSemul, NULL },
+ { DT_REG, N("statm"), PFSstatm, procfs_validfile_linux },
#ifdef __HAVE_PROCFS_MACHDEP
PROCFS_MACHDEP_NODETYPE_DEFNS
#endif
@@ -200,6 +201,8 @@ static const struct proc_target proc_root_targets[] = {
{ DT_REG, N("uptime"), PFSuptime, procfs_validfile_linux },
{ DT_REG, N("mounts"), PFSmounts, procfs_validfile_linux },
{ DT_REG, N("devices"), PFSdevices, procfs_validfile_linux },
+ { DT_REG, N("stat"), PFScpustat, procfs_validfile_linux },
+ { DT_REG, N("loadavg"), PFSloadavg, procfs_validfile_linux },
#undef N
};
static const int nproc_root_targets =
@@ -729,6 +732,7 @@ procfs_getattr(v)
case PFSmaps:
case PFScmdline:
case PFSemul:
+ case PFSstatm:
vap->va_nlink = 1;
vap->va_uid = kauth_cred_geteuid(procp->p_cred);
vap->va_gid = kauth_cred_getegid(procp->p_cred);
@@ -738,6 +742,8 @@ procfs_getattr(v)
case PFScpuinfo:
case PFSuptime:
case PFSmounts:
+ case PFScpustat:
+ case PFSloadavg:
vap->va_nlink = 1;
vap->va_uid = vap->va_gid = 0;
break;
@@ -845,6 +851,9 @@ procfs_getattr(v)
case PFScpuinfo:
case PFSuptime:
case PFSmounts:
+ case PFScpustat:
+ case PFSloadavg:
+ case PFSstatm:
vap->va_bytes = vap->va_size = 0;
break;
case PFSmap: