2009-10-19 05:25:29 +04:00
|
|
|
/* $NetBSD: procfs_linux.c,v 1.58 2009/10/19 01:25:29 dholland Exp $ */
|
2001-01-17 03:09:07 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2001 Wasabi Systems, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Written by Frank van der Linden for Wasabi Systems, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed for the NetBSD Project by
|
|
|
|
* Wasabi Systems, Inc.
|
|
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2001-11-10 16:33:40 +03:00
|
|
|
#include <sys/cdefs.h>
|
2009-10-19 05:25:29 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: procfs_linux.c,v 1.58 2009/10/19 01:25:29 dholland Exp $");
|
2001-11-10 16:33:40 +03:00
|
|
|
|
2001-01-17 03:09:07 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/vnode.h>
|
2003-08-09 17:44:39 +04:00
|
|
|
#include <sys/exec.h>
|
2003-05-28 22:03:15 +04:00
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/resourcevar.h>
|
|
|
|
#include <sys/signal.h>
|
|
|
|
#include <sys/signalvar.h>
|
|
|
|
#include <sys/tty.h>
|
2004-09-20 21:53:08 +04:00
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mount.h>
|
2006-09-20 12:09:05 +04:00
|
|
|
#include <sys/conf.h>
|
2001-01-17 03:09:07 +03:00
|
|
|
|
|
|
|
#include <miscfs/procfs/procfs.h>
|
2008-06-01 01:34:42 +04:00
|
|
|
|
2003-08-09 17:44:39 +04:00
|
|
|
#include <compat/linux/common/linux_exec.h>
|
2001-01-17 03:09:07 +03:00
|
|
|
|
|
|
|
#include <uvm/uvm_extern.h>
|
2003-05-28 22:03:15 +04:00
|
|
|
#include <uvm/uvm.h>
|
2001-01-17 03:09:07 +03:00
|
|
|
|
2006-09-20 12:09:05 +04:00
|
|
|
extern struct devsw_conv *devsw_conv;
|
|
|
|
extern int max_devsw_convs;
|
|
|
|
|
2001-01-17 03:09:07 +03:00
|
|
|
#define PGTOB(p) ((unsigned long)(p) << PAGE_SHIFT)
|
|
|
|
#define PGTOKB(p) ((unsigned long)(p) << (PAGE_SHIFT - 10))
|
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
#define LBFSZ (8 * 1024)
|
|
|
|
|
2007-05-24 04:37:40 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2007-11-11 21:29:03 +03:00
|
|
|
#ifdef LINUX_USRSTACK32
|
|
|
|
if (strcmp(p->p_emul->e_name, "linux32") == 0 &&
|
|
|
|
LINUX_USRSTACK32 < USRSTACK32)
|
|
|
|
*sstack = (unsigned long)LINUX_USRSTACK32;
|
|
|
|
else
|
|
|
|
#endif
|
2007-05-24 04:37:40 +04:00
|
|
|
#ifdef LINUX_USRSTACK
|
|
|
|
if (strcmp(p->p_emul->e_name, "linux") == 0 &&
|
|
|
|
LINUX_USRSTACK < USRSTACK)
|
2007-11-11 21:29:03 +03:00
|
|
|
*sstack = (unsigned long)LINUX_USRSTACK;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#ifdef USRSTACK32
|
|
|
|
if (strstr(p->p_emul->e_name, "32") != NULL)
|
|
|
|
*sstack = (unsigned long)USRSTACK32;
|
2007-05-24 04:37:40 +04:00
|
|
|
else
|
|
|
|
#endif
|
2007-11-11 21:29:03 +03:00
|
|
|
*sstack = (unsigned long)USRSTACK;
|
2007-05-24 04:37:40 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2001-01-17 03:09:07 +03:00
|
|
|
/*
|
|
|
|
* Linux compatible /proc/meminfo. Only active when the -o linux
|
|
|
|
* mountflag is used.
|
|
|
|
*/
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
procfs_domeminfo(struct lwp *curl, struct proc *p,
|
|
|
|
struct pfsnode *pfs, struct uio *uio)
|
2001-01-17 03:09:07 +03:00
|
|
|
{
|
2006-10-27 20:49:01 +04:00
|
|
|
char *bf;
|
2004-04-22 04:31:00 +04:00
|
|
|
int len;
|
2006-10-27 20:49:01 +04:00
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
|
2001-01-17 03:09:07 +03:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
len = snprintf(bf, LBFSZ,
|
2001-01-17 03:09:07 +03:00
|
|
|
" total: used: free: shared: buffers: cached:\n"
|
|
|
|
"Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
|
|
|
|
"Swap: %8lu %8lu %8lu\n"
|
|
|
|
"MemTotal: %8lu kB\n"
|
|
|
|
"MemFree: %8lu kB\n"
|
|
|
|
"MemShared: %8lu kB\n"
|
|
|
|
"Buffers: %8lu kB\n"
|
|
|
|
"Cached: %8lu kB\n"
|
2005-02-27 01:58:54 +03:00
|
|
|
"SwapTotal: %8lu kB\n"
|
2001-01-17 03:09:07 +03:00
|
|
|
"SwapFree: %8lu kB\n",
|
|
|
|
PGTOB(uvmexp.npages),
|
|
|
|
PGTOB(uvmexp.npages - uvmexp.free),
|
|
|
|
PGTOB(uvmexp.free),
|
|
|
|
0L,
|
2001-12-09 06:07:43 +03:00
|
|
|
PGTOB(uvmexp.filepages),
|
|
|
|
PGTOB(uvmexp.anonpages + uvmexp.filepages + uvmexp.execpages),
|
2001-01-17 03:09:07 +03:00
|
|
|
PGTOB(uvmexp.swpages),
|
|
|
|
PGTOB(uvmexp.swpginuse),
|
|
|
|
PGTOB(uvmexp.swpages - uvmexp.swpginuse),
|
|
|
|
PGTOKB(uvmexp.npages),
|
|
|
|
PGTOKB(uvmexp.free),
|
|
|
|
0L,
|
2001-12-09 06:07:43 +03:00
|
|
|
PGTOKB(uvmexp.filepages),
|
|
|
|
PGTOKB(uvmexp.anonpages + uvmexp.filepages + uvmexp.execpages),
|
2001-01-17 03:09:07 +03:00
|
|
|
PGTOKB(uvmexp.swpages),
|
|
|
|
PGTOKB(uvmexp.swpages - uvmexp.swpginuse));
|
|
|
|
|
|
|
|
if (len == 0)
|
2006-10-27 20:49:01 +04:00
|
|
|
goto out;
|
2001-01-17 03:09:07 +03:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
error = uiomove_frombuf(bf, len, uio);
|
|
|
|
out:
|
|
|
|
free(bf, M_TEMP);
|
|
|
|
return error;
|
2001-01-17 03:09:07 +03:00
|
|
|
}
|
|
|
|
|
2006-09-20 12:09:05 +04:00
|
|
|
/*
|
|
|
|
* Linux compatible /proc/devices. Only active when the -o linux
|
|
|
|
* mountflag is used.
|
|
|
|
*/
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
procfs_dodevices(struct lwp *curl, struct proc *p,
|
|
|
|
struct pfsnode *pfs, struct uio *uio)
|
2006-09-20 12:09:05 +04:00
|
|
|
{
|
2006-10-27 20:49:01 +04:00
|
|
|
char *bf;
|
2006-09-20 12:09:05 +04:00
|
|
|
int offset = 0;
|
2006-10-27 20:49:01 +04:00
|
|
|
int i, error = ENAMETOOLONG;
|
|
|
|
|
2006-12-24 19:45:23 +03:00
|
|
|
/* XXX elad - may need filtering. */
|
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
|
2006-09-20 12:09:05 +04:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
offset += snprintf(&bf[offset], LBFSZ - offset, "Character devices:\n");
|
|
|
|
if (offset >= LBFSZ)
|
|
|
|
goto out;
|
2006-09-20 12:09:05 +04:00
|
|
|
|
2008-12-29 20:41:18 +03:00
|
|
|
mutex_enter(&device_lock);
|
2006-09-20 12:09:05 +04:00
|
|
|
for (i = 0; i < max_devsw_convs; i++) {
|
|
|
|
if ((devsw_conv[i].d_name == NULL) ||
|
|
|
|
(devsw_conv[i].d_cmajor == -1))
|
|
|
|
continue;
|
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
offset += snprintf(&bf[offset], LBFSZ - offset,
|
2006-09-20 12:09:05 +04:00
|
|
|
"%3d %s\n", devsw_conv[i].d_cmajor, devsw_conv[i].d_name);
|
2007-11-07 03:23:13 +03:00
|
|
|
if (offset >= LBFSZ) {
|
2008-12-29 20:41:18 +03:00
|
|
|
mutex_exit(&device_lock);
|
2006-10-27 20:49:01 +04:00
|
|
|
goto out;
|
2007-11-07 03:23:13 +03:00
|
|
|
}
|
2006-09-20 12:09:05 +04:00
|
|
|
}
|
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
offset += snprintf(&bf[offset], LBFSZ - offset, "\nBlock devices:\n");
|
2007-11-07 03:23:13 +03:00
|
|
|
if (offset >= LBFSZ) {
|
2008-12-29 20:41:18 +03:00
|
|
|
mutex_exit(&device_lock);
|
2006-10-27 20:49:01 +04:00
|
|
|
goto out;
|
2007-11-07 03:23:13 +03:00
|
|
|
}
|
2006-09-20 12:09:05 +04:00
|
|
|
|
|
|
|
for (i = 0; i < max_devsw_convs; i++) {
|
|
|
|
if ((devsw_conv[i].d_name == NULL) ||
|
|
|
|
(devsw_conv[i].d_bmajor == -1))
|
|
|
|
continue;
|
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
offset += snprintf(&bf[offset], LBFSZ - offset,
|
2006-09-20 12:09:05 +04:00
|
|
|
"%3d %s\n", devsw_conv[i].d_bmajor, devsw_conv[i].d_name);
|
2007-11-07 03:23:13 +03:00
|
|
|
if (offset >= LBFSZ) {
|
2008-12-29 20:41:18 +03:00
|
|
|
mutex_exit(&device_lock);
|
2006-10-27 20:49:01 +04:00
|
|
|
goto out;
|
2007-11-07 03:23:13 +03:00
|
|
|
}
|
2006-09-20 12:09:05 +04:00
|
|
|
}
|
2008-12-29 20:41:18 +03:00
|
|
|
mutex_exit(&device_lock);
|
2006-09-20 12:09:05 +04:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
error = uiomove_frombuf(bf, offset, uio);
|
|
|
|
out:
|
|
|
|
free(bf, M_TEMP);
|
|
|
|
return error;
|
2006-09-20 12:09:05 +04:00
|
|
|
}
|
|
|
|
|
2007-05-24 04:37:40 +04:00
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
char *bf;
|
|
|
|
int error;
|
|
|
|
int len;
|
2007-05-25 23:20:06 +04:00
|
|
|
#if defined(MULTIPROCESSOR)
|
|
|
|
struct cpu_info *ci;
|
|
|
|
CPU_INFO_ITERATOR cii;
|
|
|
|
#endif
|
2007-05-26 02:26:14 +04:00
|
|
|
int i;
|
2007-05-24 04:37:40 +04:00
|
|
|
|
|
|
|
error = ENAMETOOLONG;
|
|
|
|
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
|
|
|
|
|
|
|
|
len = snprintf(bf, LBFSZ,
|
2007-05-24 09:33:08 +04:00
|
|
|
"cpu %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
|
2007-05-24 04:37:40 +04:00
|
|
|
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;
|
|
|
|
|
2007-05-25 23:20:06 +04:00
|
|
|
#if defined(MULTIPROCESSOR)
|
2007-05-26 02:26:14 +04:00
|
|
|
#define ALLCPUS CPU_INFO_FOREACH(cii, ci)
|
|
|
|
#define CPUNAME ci
|
|
|
|
#else
|
|
|
|
#define ALLCPUS ; i < 1 ;
|
|
|
|
#define CPUNAME curcpu()
|
|
|
|
#endif
|
|
|
|
|
2007-05-24 04:37:40 +04:00
|
|
|
i = 0;
|
2007-05-26 02:26:14 +04:00
|
|
|
for (ALLCPUS) {
|
2007-05-24 04:37:40 +04:00
|
|
|
len += snprintf(&bf[len], LBFSZ - len,
|
2007-05-24 09:33:08 +04:00
|
|
|
"cpu%d %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
|
|
|
|
"\n", i,
|
2007-05-26 02:26:14 +04:00
|
|
|
CPUNAME->ci_schedstate.spc_cp_time[CP_USER],
|
|
|
|
CPUNAME->ci_schedstate.spc_cp_time[CP_NICE],
|
|
|
|
CPUNAME->ci_schedstate.spc_cp_time[CP_SYS],
|
|
|
|
CPUNAME->ci_schedstate.spc_cp_time[CP_IDLE]);
|
2007-05-24 04:37:40 +04:00
|
|
|
if (len >= LBFSZ)
|
|
|
|
goto out;
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2007-05-25 23:20:06 +04:00
|
|
|
struct vmspace *vm;
|
2007-05-24 04:37:40 +04:00
|
|
|
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);
|
|
|
|
|
2007-05-25 23:20:06 +04:00
|
|
|
/* XXX - we use values from vmspace, since dsl says that ru figures
|
|
|
|
are always 0 except for zombies. See kvm_proc.c::kvm_getproc2() */
|
|
|
|
if ((error = proc_vmspace_getref(p, &vm)) != 0) {
|
2007-05-26 20:21:04 +04:00
|
|
|
goto out;
|
2007-05-25 23:20:06 +04:00
|
|
|
}
|
2007-05-24 04:37:40 +04:00
|
|
|
|
|
|
|
len = snprintf(bf, LBFSZ,
|
|
|
|
"%lu %lu %lu %lu %lu %lu %lu\n",
|
2007-05-25 23:20:06 +04:00
|
|
|
(unsigned long)(vm->vm_tsize + vm->vm_dsize + vm->vm_ssize), /* size */
|
|
|
|
(unsigned long)(vm->vm_rssize), /* resident */
|
|
|
|
(unsigned long)(ru->ru_ixrss), /* shared */
|
|
|
|
(unsigned long)(vm->vm_tsize), /* text size in pages */
|
|
|
|
(unsigned long)(vm->vm_dsize), /* data size in pages */
|
|
|
|
(unsigned long)(vm->vm_ssize), /* stack size in pages */
|
2007-05-24 04:37:40 +04:00
|
|
|
(unsigned long) 0);
|
2007-05-25 23:20:06 +04:00
|
|
|
|
2009-10-19 05:25:29 +04:00
|
|
|
uvmspace_free(vm);
|
|
|
|
|
2007-05-24 04:37:40 +04:00
|
|
|
if (len == 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
error = uiomove_frombuf(bf, len, uio);
|
|
|
|
out:
|
|
|
|
free(bf, M_TEMP);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2007-05-25 23:20:06 +04:00
|
|
|
#define USEC_2_TICKS(x) ((x) / 10000)
|
|
|
|
|
2003-05-28 22:03:15 +04:00
|
|
|
/*
|
|
|
|
* Linux compatible /proc/<pid>/stat. Only active when the -o linux
|
|
|
|
* mountflag is used.
|
|
|
|
*/
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
procfs_do_pid_stat(struct lwp *curl, struct lwp *l,
|
|
|
|
struct pfsnode *pfs, struct uio *uio)
|
2003-05-28 22:03:15 +04:00
|
|
|
{
|
2006-10-27 20:49:01 +04:00
|
|
|
char *bf;
|
2006-06-24 20:34:02 +04:00
|
|
|
struct proc *p = l->l_proc;
|
2004-04-22 04:31:00 +04:00
|
|
|
int len;
|
2003-05-28 22:03:15 +04:00
|
|
|
struct tty *tty = p->p_session->s_ttyp;
|
|
|
|
struct rusage *ru = &p->p_stats->p_ru;
|
|
|
|
struct rusage *cru = &p->p_stats->p_cru;
|
|
|
|
unsigned long stext = 0, etext = 0, sstack = 0;
|
2007-02-10 00:55:00 +03:00
|
|
|
struct timeval rt;
|
2007-05-26 20:21:04 +04:00
|
|
|
struct vmspace *vm;
|
2006-10-27 20:49:01 +04:00
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
|
2003-05-28 22:03:15 +04:00
|
|
|
|
2007-05-26 20:21:04 +04:00
|
|
|
if ((error = proc_vmspace_getref(p, &vm)) != 0) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2007-05-24 04:37:40 +04:00
|
|
|
get_proc_size_info(l, &stext, &etext, &sstack);
|
2007-02-10 00:55:00 +03:00
|
|
|
|
2008-04-24 19:35:27 +04:00
|
|
|
mutex_enter(proc_lock);
|
2008-04-24 22:39:20 +04:00
|
|
|
mutex_enter(p->p_lock);
|
2007-02-10 00:55:00 +03:00
|
|
|
|
|
|
|
calcru(p, NULL, NULL, NULL, &rt);
|
2003-05-28 22:03:15 +04:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
len = snprintf(bf, LBFSZ,
|
2009-01-11 05:45:45 +03:00
|
|
|
"%d (%s) %c %d %d %d %lld %d "
|
2003-05-28 22:03:15 +04:00
|
|
|
"%u "
|
|
|
|
"%lu %lu %lu %lu %lu %lu %lu %lu "
|
|
|
|
"%d %d %d "
|
2009-01-11 05:45:45 +03:00
|
|
|
"%lld %lld %lu %lu %" PRIu64 " "
|
2003-05-28 22:03:15 +04:00
|
|
|
"%lu %lu %lu "
|
|
|
|
"%u %u "
|
|
|
|
"%u %u %u %u "
|
|
|
|
"%lu %lu %lu %d %d\n",
|
|
|
|
|
|
|
|
p->p_pid,
|
|
|
|
p->p_comm,
|
|
|
|
"0IR3SZD"[(p->p_stat > 6) ? 0 : (int)p->p_stat],
|
2006-10-23 22:19:14 +04:00
|
|
|
(p->p_pptr != NULL) ? p->p_pptr->p_pid : 0,
|
2003-05-28 22:03:15 +04:00
|
|
|
|
|
|
|
p->p_pgid,
|
|
|
|
p->p_session->s_sid,
|
2009-01-11 06:16:33 +03:00
|
|
|
(unsigned long long)(tty ? tty->t_dev : 0),
|
2003-10-30 17:51:01 +03:00
|
|
|
(tty && tty->t_pgrp) ? tty->t_pgrp->pg_id : 0,
|
2003-05-28 22:03:15 +04:00
|
|
|
|
|
|
|
p->p_flag,
|
|
|
|
|
|
|
|
ru->ru_minflt,
|
|
|
|
cru->ru_minflt,
|
|
|
|
ru->ru_majflt,
|
|
|
|
cru->ru_majflt,
|
2009-01-11 05:45:45 +03:00
|
|
|
(long)USEC_2_TICKS(ru->ru_utime.tv_usec),
|
|
|
|
(long)USEC_2_TICKS(ru->ru_stime.tv_usec),
|
|
|
|
(long)USEC_2_TICKS(cru->ru_utime.tv_usec),
|
|
|
|
(long)USEC_2_TICKS(cru->ru_stime.tv_usec),
|
2003-05-28 22:03:15 +04:00
|
|
|
|
2007-05-26 02:26:14 +04:00
|
|
|
l->l_priority, /* XXX: priority */
|
2007-05-26 20:21:04 +04:00
|
|
|
p->p_nice - 20,
|
2003-05-28 22:03:15 +04:00
|
|
|
0,
|
|
|
|
|
2009-01-11 05:45:45 +03:00
|
|
|
(long long)rt.tv_sec,
|
|
|
|
(long long)p->p_stats->p_start.tv_sec,
|
2007-05-26 20:21:04 +04:00
|
|
|
(unsigned long)(vm->vm_tsize + vm->vm_dsize + vm->vm_ssize), /* size */
|
|
|
|
(unsigned long)(vm->vm_rssize), /* resident */
|
2003-05-28 22:03:15 +04:00
|
|
|
p->p_rlimit[RLIMIT_RSS].rlim_cur,
|
|
|
|
|
|
|
|
stext, /* start code */
|
|
|
|
etext, /* end code */
|
|
|
|
sstack, /* mm start stack */
|
|
|
|
0, /* XXX: pc */
|
|
|
|
0, /* XXX: sp */
|
2007-02-10 00:55:00 +03:00
|
|
|
p->p_sigpend.sp_set.__bits[0], /* XXX: pending */
|
|
|
|
0, /* XXX: held */
|
2003-05-28 22:03:15 +04:00
|
|
|
p->p_sigctx.ps_sigignore.__bits[0], /* ignored */
|
|
|
|
p->p_sigctx.ps_sigcatch.__bits[0], /* caught */
|
|
|
|
|
|
|
|
(unsigned long)(intptr_t)l->l_wchan,
|
|
|
|
ru->ru_nvcsw,
|
|
|
|
ru->ru_nivcsw,
|
|
|
|
p->p_exitsig,
|
|
|
|
0); /* XXX: processor */
|
|
|
|
|
2008-04-24 22:39:20 +04:00
|
|
|
mutex_exit(p->p_lock);
|
2008-04-24 19:35:27 +04:00
|
|
|
mutex_exit(proc_lock);
|
2007-02-10 00:55:00 +03:00
|
|
|
|
2009-10-19 05:25:29 +04:00
|
|
|
uvmspace_free(vm);
|
|
|
|
|
2003-05-28 22:03:15 +04:00
|
|
|
if (len == 0)
|
2006-10-27 20:49:01 +04:00
|
|
|
goto out;
|
2003-05-28 22:03:15 +04:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
error = uiomove_frombuf(bf, len, uio);
|
|
|
|
out:
|
|
|
|
free(bf, M_TEMP);
|
|
|
|
return error;
|
2003-05-28 22:03:15 +04:00
|
|
|
}
|
|
|
|
|
2001-01-17 03:09:07 +03:00
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
procfs_docpuinfo(struct lwp *curl, struct proc *p,
|
|
|
|
struct pfsnode *pfs, struct uio *uio)
|
2001-01-17 03:09:07 +03:00
|
|
|
{
|
2006-10-27 20:49:01 +04:00
|
|
|
int len = LBFSZ;
|
2005-05-30 01:55:33 +04:00
|
|
|
char *bf = malloc(len, M_TEMP, M_WAITOK);
|
2005-02-28 01:29:50 +03:00
|
|
|
int error;
|
2001-01-17 03:09:07 +03:00
|
|
|
|
2005-05-30 01:55:33 +04:00
|
|
|
if (procfs_getcpuinfstr(bf, &len) < 0) {
|
2005-02-28 01:29:50 +03:00
|
|
|
error = ENOSPC;
|
|
|
|
goto done;
|
|
|
|
}
|
2001-01-17 03:09:07 +03:00
|
|
|
|
2005-02-28 01:29:50 +03:00
|
|
|
if (len == 0) {
|
|
|
|
error = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
2001-01-17 03:09:07 +03:00
|
|
|
|
2005-05-30 01:55:33 +04:00
|
|
|
error = uiomove_frombuf(bf, len, uio);
|
2005-02-28 01:29:50 +03:00
|
|
|
done:
|
2005-05-30 01:55:33 +04:00
|
|
|
free(bf, M_TEMP);
|
2005-02-28 01:29:50 +03:00
|
|
|
return error;
|
2001-01-17 03:09:07 +03:00
|
|
|
}
|
2003-02-26 00:00:31 +03:00
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
procfs_douptime(struct lwp *curl, struct proc *p,
|
|
|
|
struct pfsnode *pfs, struct uio *uio)
|
2003-02-26 00:00:31 +03:00
|
|
|
{
|
2006-10-27 20:49:01 +04:00
|
|
|
char *bf;
|
2004-04-22 04:31:00 +04:00
|
|
|
int len;
|
2003-02-26 00:00:31 +03:00
|
|
|
struct timeval runtime;
|
|
|
|
u_int64_t idle;
|
2006-10-27 20:49:01 +04:00
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
|
2003-02-26 00:00:31 +03:00
|
|
|
|
2007-12-22 04:06:54 +03:00
|
|
|
microuptime(&runtime);
|
2003-02-26 00:00:31 +03:00
|
|
|
idle = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE];
|
2006-10-27 20:49:01 +04:00
|
|
|
len = snprintf(bf, LBFSZ,
|
2009-01-11 05:45:45 +03:00
|
|
|
"%lld.%02lu %" PRIu64 ".%02" PRIu64 "\n",
|
|
|
|
(long long)runtime.tv_sec, (long)runtime.tv_usec / 10000,
|
2004-04-22 04:31:00 +04:00
|
|
|
idle / hz, (((idle % hz) * 100) / hz) % 100);
|
2003-02-26 00:00:31 +03:00
|
|
|
|
|
|
|
if (len == 0)
|
2006-10-27 20:49:01 +04:00
|
|
|
goto out;
|
2003-02-26 00:00:31 +03:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
error = uiomove_frombuf(bf, len, uio);
|
|
|
|
out:
|
|
|
|
free(bf, M_TEMP);
|
|
|
|
return error;
|
2003-02-26 00:00:31 +03:00
|
|
|
}
|
2004-09-20 21:53:08 +04:00
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
procfs_domounts(struct lwp *curl, struct proc *p,
|
|
|
|
struct pfsnode *pfs, struct uio *uio)
|
2004-09-20 21:53:08 +04:00
|
|
|
{
|
2006-10-27 20:49:01 +04:00
|
|
|
char *bf, *mtab = NULL;
|
2004-09-20 21:53:08 +04:00
|
|
|
const char *fsname;
|
|
|
|
size_t len, mtabsz = 0;
|
|
|
|
struct mount *mp, *nmp;
|
|
|
|
struct statvfs *sfs;
|
|
|
|
int error = 0;
|
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
|
2007-10-11 00:42:20 +04:00
|
|
|
mutex_enter(&mountlist_lock);
|
2004-09-20 21:53:08 +04:00
|
|
|
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
|
|
|
|
mp = nmp) {
|
PR kern/38141 lookup/vfs_busy acquire rwlock recursively
Simplify the mount locking. Remove all the crud to deal with recursion on
the mount lock, and crud to deal with unmount as another weirdo lock.
Hopefully this will once and for all fix the deadlocks with this. With this
commit there are two locks on each mount:
- krwlock_t mnt_unmounting. This is used to prevent unmount across critical
sections like getnewvnode(). It's only ever read locked with rw_tryenter(),
and is only ever write locked in dounmount(). A write hold can't be taken
on this lock if the current LWP could hold a vnode lock.
- kmutex_t mnt_updating. This is taken by threads updating the mount, for
example when going r/o -> r/w, and is only present to serialize updates.
In order to take this lock, a read hold must first be taken on
mnt_unmounting, and the two need to be held across the operation.
One effect of this change: previously if an unmount failed, we would make a
half hearted attempt to back out of it gracefully, but that was unlikely to
work in a lot of cases. Now while an unmount that will be aborted is in
progress, new file operations within the mount will fail instead of being
delayed. That is unlikely to be a problem though, because if the admin
requests unmount of a file system then s(he) has made a decision to deny
access to the resource.
2008-05-06 22:43:44 +04:00
|
|
|
if (vfs_busy(mp, &nmp)) {
|
2004-09-20 21:53:08 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfs = &mp->mnt_stat;
|
|
|
|
|
|
|
|
/* Linux uses different names for some filesystems */
|
|
|
|
fsname = sfs->f_fstypename;
|
|
|
|
if (strcmp(fsname, "procfs") == 0)
|
|
|
|
fsname = "proc";
|
|
|
|
else if (strcmp(fsname, "ext2fs") == 0)
|
|
|
|
fsname = "ext2";
|
2005-02-27 01:58:54 +03:00
|
|
|
|
2006-10-27 20:49:01 +04:00
|
|
|
len = snprintf(bf, LBFSZ, "%s %s %s %s%s%s%s%s%s 0 0\n",
|
2004-09-20 21:53:08 +04:00
|
|
|
sfs->f_mntfromname,
|
|
|
|
sfs->f_mntonname,
|
|
|
|
fsname,
|
|
|
|
(mp->mnt_flag & MNT_RDONLY) ? "ro" : "rw",
|
|
|
|
(mp->mnt_flag & MNT_NOSUID) ? ",nosuid" : "",
|
|
|
|
(mp->mnt_flag & MNT_NOEXEC) ? ",noexec" : "",
|
|
|
|
(mp->mnt_flag & MNT_NODEV) ? ",nodev" : "",
|
|
|
|
(mp->mnt_flag & MNT_SYNCHRONOUS) ? ",sync" : "",
|
|
|
|
(mp->mnt_flag & MNT_NOATIME) ? ",noatime" : ""
|
|
|
|
);
|
|
|
|
|
|
|
|
mtab = realloc(mtab, mtabsz + len, M_TEMP, M_WAITOK);
|
2005-05-30 01:55:33 +04:00
|
|
|
memcpy(mtab + mtabsz, bf, len);
|
2004-09-20 21:53:08 +04:00
|
|
|
mtabsz += len;
|
|
|
|
|
2008-04-30 16:49:16 +04:00
|
|
|
vfs_unbusy(mp, false, &nmp);
|
2004-09-20 21:53:08 +04:00
|
|
|
}
|
2007-10-11 00:42:20 +04:00
|
|
|
mutex_exit(&mountlist_lock);
|
2006-10-27 20:49:01 +04:00
|
|
|
free(bf, M_TEMP);
|
2004-09-20 21:53:08 +04:00
|
|
|
|
|
|
|
if (mtabsz > 0) {
|
|
|
|
error = uiomove_frombuf(mtab, mtabsz, uio);
|
|
|
|
free(mtab, M_TEMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|