1 /* $NetBSD: procfs_linux.c,v 1.57 2009/01/11 03:16:33 christos Exp $ */
4 * Copyright (c) 2001 Wasabi Systems, Inc.
7 * Written by Frank van der Linden for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: procfs_linux.c,v 1.57 2009/01/11 03:16:33 christos Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
44 #include <sys/kernel.h>
46 #include <sys/vnode.h>
48 #include <sys/resource.h>
49 #include <sys/resourcevar.h>
50 #include <sys/signal.h>
51 #include <sys/signalvar.h>
53 #include <sys/malloc.h>
54 #include <sys/mount.h>
57 #include <miscfs/procfs/procfs.h>
59 #include <compat/linux/common/linux_exec.h>
61 #include <uvm/uvm_extern.h>
64 extern struct devsw_conv
*devsw_conv
;
65 extern int max_devsw_convs
;
67 #define PGTOB(p) ((unsigned long)(p) << PAGE_SHIFT)
68 #define PGTOKB(p) ((unsigned long)(p) << (PAGE_SHIFT - 10))
70 #define LBFSZ (8 * 1024)
73 get_proc_size_info(struct lwp
*l
, unsigned long *stext
, unsigned long *etext
, unsigned long *sstack
)
75 struct proc
*p
= l
->l_proc
;
78 struct vm_map_entry
*entry
;
84 proc_vmspace_getref(p
, &vm
);
86 vm_map_lock_read(map
);
88 for (entry
= map
->header
.next
; entry
!= &map
->header
;
89 entry
= entry
->next
) {
90 if (UVM_ET_ISSUBMAP(entry
))
92 /* assume text is the first entry */
93 if (*stext
== *etext
) {
94 *stext
= entry
->start
;
99 #ifdef LINUX_USRSTACK32
100 if (strcmp(p
->p_emul
->e_name
, "linux32") == 0 &&
101 LINUX_USRSTACK32
< USRSTACK32
)
102 *sstack
= (unsigned long)LINUX_USRSTACK32
;
105 #ifdef LINUX_USRSTACK
106 if (strcmp(p
->p_emul
->e_name
, "linux") == 0 &&
107 LINUX_USRSTACK
< USRSTACK
)
108 *sstack
= (unsigned long)LINUX_USRSTACK
;
112 if (strstr(p
->p_emul
->e_name
, "32") != NULL
)
113 *sstack
= (unsigned long)USRSTACK32
;
116 *sstack
= (unsigned long)USRSTACK
;
119 * jdk 1.6 compares low <= addr && addr < high
120 * if we put addr == high, then the test fails
123 *sstack
-= PAGE_SIZE
;
125 vm_map_unlock_read(map
);
130 * Linux compatible /proc/meminfo. Only active when the -o linux
134 procfs_domeminfo(struct lwp
*curl
, struct proc
*p
,
135 struct pfsnode
*pfs
, struct uio
*uio
)
141 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
143 len
= snprintf(bf
, LBFSZ
,
144 " total: used: free: shared: buffers: cached:\n"
145 "Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
146 "Swap: %8lu %8lu %8lu\n"
147 "MemTotal: %8lu kB\n"
149 "MemShared: %8lu kB\n"
152 "SwapTotal: %8lu kB\n"
153 "SwapFree: %8lu kB\n",
154 PGTOB(uvmexp
.npages
),
155 PGTOB(uvmexp
.npages
- uvmexp
.free
),
158 PGTOB(uvmexp
.filepages
),
159 PGTOB(uvmexp
.anonpages
+ uvmexp
.filepages
+ uvmexp
.execpages
),
160 PGTOB(uvmexp
.swpages
),
161 PGTOB(uvmexp
.swpginuse
),
162 PGTOB(uvmexp
.swpages
- uvmexp
.swpginuse
),
163 PGTOKB(uvmexp
.npages
),
166 PGTOKB(uvmexp
.filepages
),
167 PGTOKB(uvmexp
.anonpages
+ uvmexp
.filepages
+ uvmexp
.execpages
),
168 PGTOKB(uvmexp
.swpages
),
169 PGTOKB(uvmexp
.swpages
- uvmexp
.swpginuse
));
174 error
= uiomove_frombuf(bf
, len
, uio
);
181 * Linux compatible /proc/devices. Only active when the -o linux
185 procfs_dodevices(struct lwp
*curl
, struct proc
*p
,
186 struct pfsnode
*pfs
, struct uio
*uio
)
190 int i
, error
= ENAMETOOLONG
;
192 /* XXX elad - may need filtering. */
194 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
196 offset
+= snprintf(&bf
[offset
], LBFSZ
- offset
, "Character devices:\n");
200 mutex_enter(&device_lock
);
201 for (i
= 0; i
< max_devsw_convs
; i
++) {
202 if ((devsw_conv
[i
].d_name
== NULL
) ||
203 (devsw_conv
[i
].d_cmajor
== -1))
206 offset
+= snprintf(&bf
[offset
], LBFSZ
- offset
,
207 "%3d %s\n", devsw_conv
[i
].d_cmajor
, devsw_conv
[i
].d_name
);
208 if (offset
>= LBFSZ
) {
209 mutex_exit(&device_lock
);
214 offset
+= snprintf(&bf
[offset
], LBFSZ
- offset
, "\nBlock devices:\n");
215 if (offset
>= LBFSZ
) {
216 mutex_exit(&device_lock
);
220 for (i
= 0; i
< max_devsw_convs
; i
++) {
221 if ((devsw_conv
[i
].d_name
== NULL
) ||
222 (devsw_conv
[i
].d_bmajor
== -1))
225 offset
+= snprintf(&bf
[offset
], LBFSZ
- offset
,
226 "%3d %s\n", devsw_conv
[i
].d_bmajor
, devsw_conv
[i
].d_name
);
227 if (offset
>= LBFSZ
) {
228 mutex_exit(&device_lock
);
232 mutex_exit(&device_lock
);
234 error
= uiomove_frombuf(bf
, offset
, uio
);
241 * Linux compatible /proc/stat. Only active when the -o linux
245 procfs_docpustat(struct lwp
*curl
, struct proc
*p
,
246 struct pfsnode
*pfs
, struct uio
*uio
)
251 #if defined(MULTIPROCESSOR)
253 CPU_INFO_ITERATOR cii
;
257 error
= ENAMETOOLONG
;
258 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
260 len
= snprintf(bf
, LBFSZ
,
261 "cpu %" PRIu64
" %" PRIu64
" %" PRIu64
" %" PRIu64
"\n",
262 curcpu()->ci_schedstate
.spc_cp_time
[CP_USER
],
263 curcpu()->ci_schedstate
.spc_cp_time
[CP_NICE
],
264 curcpu()->ci_schedstate
.spc_cp_time
[CP_SYS
] /*+ [CP_INTR]*/,
265 curcpu()->ci_schedstate
.spc_cp_time
[CP_IDLE
]);
269 #if defined(MULTIPROCESSOR)
270 #define ALLCPUS CPU_INFO_FOREACH(cii, ci)
273 #define ALLCPUS ; i < 1 ;
274 #define CPUNAME curcpu()
279 len
+= snprintf(&bf
[len
], LBFSZ
- len
,
280 "cpu%d %" PRIu64
" %" PRIu64
" %" PRIu64
" %" PRIu64
282 CPUNAME
->ci_schedstate
.spc_cp_time
[CP_USER
],
283 CPUNAME
->ci_schedstate
.spc_cp_time
[CP_NICE
],
284 CPUNAME
->ci_schedstate
.spc_cp_time
[CP_SYS
],
285 CPUNAME
->ci_schedstate
.spc_cp_time
[CP_IDLE
]);
291 len
+= snprintf(&bf
[len
], LBFSZ
- len
,
298 uvmexp
.pageins
, uvmexp
.pdpageouts
,
299 uvmexp
.pgswapin
, uvmexp
.pgswapout
,
302 (long long)boottime
.tv_sec
);
306 error
= uiomove_frombuf(bf
, len
, uio
);
313 * Linux compatible /proc/loadavg. Only active when the -o linux
317 procfs_doloadavg(struct lwp
*curl
, struct proc
*p
,
318 struct pfsnode
*pfs
, struct uio
*uio
)
324 error
= ENAMETOOLONG
;
325 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
327 averunnable
.fscale
= FSCALE
;
328 len
= snprintf(bf
, LBFSZ
,
329 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
330 (int)(averunnable
.ldavg
[0] / averunnable
.fscale
),
331 (int)(averunnable
.ldavg
[0] * 100 / averunnable
.fscale
% 100),
332 (int)(averunnable
.ldavg
[1] / averunnable
.fscale
),
333 (int)(averunnable
.ldavg
[1] * 100 / averunnable
.fscale
% 100),
334 (int)(averunnable
.ldavg
[2] / averunnable
.fscale
),
335 (int)(averunnable
.ldavg
[2] * 100 / averunnable
.fscale
% 100),
336 1, /* number of ONPROC processes */
338 30000); /* last pid */
342 error
= uiomove_frombuf(bf
, len
, uio
);
349 * Linux compatible /proc/<pid>/statm. Only active when the -o linux
353 procfs_do_pid_statm(struct lwp
*curl
, struct lwp
*l
,
354 struct pfsnode
*pfs
, struct uio
*uio
)
357 struct proc
*p
= l
->l_proc
;
358 struct rusage
*ru
= &p
->p_stats
->p_ru
;
363 error
= ENAMETOOLONG
;
364 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
366 /* XXX - we use values from vmspace, since dsl says that ru figures
367 are always 0 except for zombies. See kvm_proc.c::kvm_getproc2() */
368 if ((error
= proc_vmspace_getref(p
, &vm
)) != 0) {
372 len
= snprintf(bf
, LBFSZ
,
373 "%lu %lu %lu %lu %lu %lu %lu\n",
374 (unsigned long)(vm
->vm_tsize
+ vm
->vm_dsize
+ vm
->vm_ssize
), /* size */
375 (unsigned long)(vm
->vm_rssize
), /* resident */
376 (unsigned long)(ru
->ru_ixrss
), /* shared */
377 (unsigned long)(vm
->vm_tsize
), /* text size in pages */
378 (unsigned long)(vm
->vm_dsize
), /* data size in pages */
379 (unsigned long)(vm
->vm_ssize
), /* stack size in pages */
387 error
= uiomove_frombuf(bf
, len
, uio
);
393 #define USEC_2_TICKS(x) ((x) / 10000)
396 * Linux compatible /proc/<pid>/stat. Only active when the -o linux
400 procfs_do_pid_stat(struct lwp
*curl
, struct lwp
*l
,
401 struct pfsnode
*pfs
, struct uio
*uio
)
404 struct proc
*p
= l
->l_proc
;
406 struct tty
*tty
= p
->p_session
->s_ttyp
;
407 struct rusage
*ru
= &p
->p_stats
->p_ru
;
408 struct rusage
*cru
= &p
->p_stats
->p_cru
;
409 unsigned long stext
= 0, etext
= 0, sstack
= 0;
414 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
416 if ((error
= proc_vmspace_getref(p
, &vm
)) != 0) {
420 get_proc_size_info(l
, &stext
, &etext
, &sstack
);
422 mutex_enter(proc_lock
);
423 mutex_enter(p
->p_lock
);
425 calcru(p
, NULL
, NULL
, NULL
, &rt
);
427 len
= snprintf(bf
, LBFSZ
,
428 "%d (%s) %c %d %d %d %lld %d "
430 "%lu %lu %lu %lu %lu %lu %lu %lu "
432 "%lld %lld %lu %lu %" PRIu64
" "
436 "%lu %lu %lu %d %d\n",
440 "0IR3SZD"[(p
->p_stat
> 6) ? 0 : (int)p
->p_stat
],
441 (p
->p_pptr
!= NULL
) ? p
->p_pptr
->p_pid
: 0,
445 (unsigned long long)(tty
? tty
->t_dev
: 0),
446 (tty
&& tty
->t_pgrp
) ? tty
->t_pgrp
->pg_id
: 0,
454 (long)USEC_2_TICKS(ru
->ru_utime
.tv_usec
),
455 (long)USEC_2_TICKS(ru
->ru_stime
.tv_usec
),
456 (long)USEC_2_TICKS(cru
->ru_utime
.tv_usec
),
457 (long)USEC_2_TICKS(cru
->ru_stime
.tv_usec
),
459 l
->l_priority
, /* XXX: priority */
463 (long long)rt
.tv_sec
,
464 (long long)p
->p_stats
->p_start
.tv_sec
,
465 (unsigned long)(vm
->vm_tsize
+ vm
->vm_dsize
+ vm
->vm_ssize
), /* size */
466 (unsigned long)(vm
->vm_rssize
), /* resident */
467 p
->p_rlimit
[RLIMIT_RSS
].rlim_cur
,
469 stext
, /* start code */
470 etext
, /* end code */
471 sstack
, /* mm start stack */
474 p
->p_sigpend
.sp_set
.__bits
[0], /* XXX: pending */
476 p
->p_sigctx
.ps_sigignore
.__bits
[0], /* ignored */
477 p
->p_sigctx
.ps_sigcatch
.__bits
[0], /* caught */
479 (unsigned long)(intptr_t)l
->l_wchan
,
483 0); /* XXX: processor */
485 mutex_exit(p
->p_lock
);
486 mutex_exit(proc_lock
);
493 error
= uiomove_frombuf(bf
, len
, uio
);
500 procfs_docpuinfo(struct lwp
*curl
, struct proc
*p
,
501 struct pfsnode
*pfs
, struct uio
*uio
)
504 char *bf
= malloc(len
, M_TEMP
, M_WAITOK
);
507 if (procfs_getcpuinfstr(bf
, &len
) < 0) {
517 error
= uiomove_frombuf(bf
, len
, uio
);
524 procfs_douptime(struct lwp
*curl
, struct proc
*p
,
525 struct pfsnode
*pfs
, struct uio
*uio
)
529 struct timeval runtime
;
533 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
535 microuptime(&runtime
);
536 idle
= curcpu()->ci_schedstate
.spc_cp_time
[CP_IDLE
];
537 len
= snprintf(bf
, LBFSZ
,
538 "%lld.%02lu %" PRIu64
".%02" PRIu64
"\n",
539 (long long)runtime
.tv_sec
, (long)runtime
.tv_usec
/ 10000,
540 idle
/ hz
, (((idle
% hz
) * 100) / hz
) % 100);
545 error
= uiomove_frombuf(bf
, len
, uio
);
552 procfs_domounts(struct lwp
*curl
, struct proc
*p
,
553 struct pfsnode
*pfs
, struct uio
*uio
)
555 char *bf
, *mtab
= NULL
;
557 size_t len
, mtabsz
= 0;
558 struct mount
*mp
, *nmp
;
562 bf
= malloc(LBFSZ
, M_TEMP
, M_WAITOK
);
563 mutex_enter(&mountlist_lock
);
564 for (mp
= CIRCLEQ_FIRST(&mountlist
); mp
!= (void *)&mountlist
;
566 if (vfs_busy(mp
, &nmp
)) {
572 /* Linux uses different names for some filesystems */
573 fsname
= sfs
->f_fstypename
;
574 if (strcmp(fsname
, "procfs") == 0)
576 else if (strcmp(fsname
, "ext2fs") == 0)
579 len
= snprintf(bf
, LBFSZ
, "%s %s %s %s%s%s%s%s%s 0 0\n",
583 (mp
->mnt_flag
& MNT_RDONLY
) ? "ro" : "rw",
584 (mp
->mnt_flag
& MNT_NOSUID
) ? ",nosuid" : "",
585 (mp
->mnt_flag
& MNT_NOEXEC
) ? ",noexec" : "",
586 (mp
->mnt_flag
& MNT_NODEV
) ? ",nodev" : "",
587 (mp
->mnt_flag
& MNT_SYNCHRONOUS
) ? ",sync" : "",
588 (mp
->mnt_flag
& MNT_NOATIME
) ? ",noatime" : ""
591 mtab
= realloc(mtab
, mtabsz
+ len
, M_TEMP
, M_WAITOK
);
592 memcpy(mtab
+ mtabsz
, bf
, len
);
595 vfs_unbusy(mp
, false, &nmp
);
597 mutex_exit(&mountlist_lock
);
601 error
= uiomove_frombuf(mtab
, mtabsz
, uio
);