diff options
| author | agc <agc@NetBSD.org> | 2007-05-24 00:37:40 +0000 |
|---|---|---|
| committer | agc <agc@NetBSD.org> | 2007-05-24 00:37:40 +0000 |
| commit | 4dbe5ed7e761dc649d5ed976ae217050e22cfcdc (patch) | |
| tree | 6b4e735bdd365f09e5149e832f3e7f3afe938449 /sys | |
| parent | 94b0103837aad4ca66af65b37e23c61ec987398d (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.h | 11 | ||||
| -rw-r--r-- | sys/miscfs/procfs/procfs_linux.c | 223 | ||||
| -rw-r--r-- | sys/miscfs/procfs/procfs_subr.c | 19 | ||||
| -rw-r--r-- | sys/miscfs/procfs/procfs_vnops.c | 13 |
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: |
