2 * linux/fs/proc/array.c
4 * Copyright (C) 1992 by Linus Torvalds
5 * based on ideas by Darren Senn
8 * Michael. K. Johnson: stat,statm extensions.
9 * <johnsonm@stolaf.edu>
11 * Pauline Middelink : Made cmdline,envline only break at '\0's, to
12 * make sure SET_PROCTITLE works. Also removed
13 * bad '!' which forced address recalculation for
14 * EVERY character on the current page.
15 * <middelin@polyware.iaf.nl>
17 * Danny ter Haar : added cpuinfo
20 * Alessandro Rubini : profile extension.
21 * <rubini@ipvvis.unipv.it>
23 * Jeff Tranter : added BogoMips field to cpuinfo
24 * <Jeff_Tranter@Mitel.COM>
26 * Bruno Haible : remove 4K limit for the maps file
27 * <haible@ma2s2.mathematik.uni-karlsruhe.de>
29 * Yves Arrouye : remove removal of trailing spaces in get_array.
30 * <Yves.Arrouye@marin.fdn.fr>
32 * Jerome Forissier : added per-CPU time information to /proc/stat
33 * and /proc/<pid>/cpu extension
34 * <forissier@isia.cma.fr>
35 * - Incorporation and non-SMP safe operation
36 * of forissier patch in 2.1.78 by
37 * Hans Marcus <crowbar@concepts.nl>
39 * aeb@cwi.nl : /proc/partitions
42 * Alan Cox : security fixes.
43 * <Alan.Cox@linux.org>
45 * Al Viro : safe handling of mm_struct
47 * Gerhard Wichert : added BIGMEM support
48 * Siemens AG <Gerhard.Wichert@pdb.siemens.de>
50 * Al Viro & Jeff Garzik : moved most of the thing into base.c and
51 * : proc_misc.c. The rest may eventually go into
55 #include <linux/config.h>
56 #include <linux/types.h>
57 #include <linux/errno.h>
58 #include <linux/sched.h>
59 #include <linux/kernel.h>
60 #include <linux/kernel_stat.h>
61 #include <linux/tty.h>
62 #include <linux/string.h>
63 #include <linux/mman.h>
64 #include <linux/proc_fs.h>
65 #include <linux/ioport.h>
67 #include <linux/pagemap.h>
68 #include <linux/swap.h>
69 #include <linux/slab.h>
70 #include <linux/smp.h>
71 #include <linux/signal.h>
72 #include <linux/highmem.h>
74 #include <asm/uaccess.h>
75 #include <asm/pgtable.h>
77 #include <asm/processor.h>
79 /* Gcc optimizes away "strlen(x)" for constant x */
80 #define ADDBUF(buffer, string) \
81 do { memcpy(buffer, string, strlen(string)); \
82 buffer += strlen(string); } while (0)
84 static inline char * task_name(struct task_struct
*p
, char * buf
)
89 ADDBUF(buf
, "Name:\t");
93 unsigned char c
= *name
;
117 * The task state array is a strange "bitmap" of
118 * reasons to sleep. Thus "running" is zero, and
119 * you can test for combinations of others with
122 static const char *task_state_array
[] = {
123 "R (running)", /* 0 */
124 "S (sleeping)", /* 1 */
125 "D (disk sleep)", /* 2 */
126 "Z (zombie)", /* 4 */
127 "T (stopped)", /* 8 */
128 "W (paging)" /* 16 */
131 static inline const char * get_task_state(struct task_struct
*tsk
)
133 unsigned int state
= tsk
->state
& (TASK_RUNNING
|
135 TASK_UNINTERRUPTIBLE
|
138 const char **p
= &task_state_array
[0];
147 static inline char * task_state(struct task_struct
*p
, char *buffer
)
151 read_lock(&tasklist_lock
);
152 buffer
+= sprintf(buffer
,
157 "Uid:\t%d\t%d\t%d\t%d\n"
158 "Gid:\t%d\t%d\t%d\t%d\n",
160 p
->pid
, p
->p_opptr
->pid
, p
->p_pptr
->pid
!= p
->p_opptr
->pid
? p
->p_opptr
->pid
: 0,
161 p
->uid
, p
->euid
, p
->suid
, p
->fsuid
,
162 p
->gid
, p
->egid
, p
->sgid
, p
->fsgid
);
163 read_unlock(&tasklist_lock
);
165 buffer
+= sprintf(buffer
,
168 p
->files
? p
->files
->max_fds
: 0);
171 for (g
= 0; g
< p
->ngroups
; g
++)
172 buffer
+= sprintf(buffer
, "%d ", p
->groups
[g
]);
174 buffer
+= sprintf(buffer
, "\n");
178 static inline char * task_mem(struct mm_struct
*mm
, char *buffer
)
180 struct vm_area_struct
* vma
;
181 unsigned long data
= 0, stack
= 0;
182 unsigned long exec
= 0, lib
= 0;
185 for (vma
= mm
->mmap
; vma
; vma
= vma
->vm_next
) {
186 unsigned long len
= (vma
->vm_end
- vma
->vm_start
) >> 10;
189 if (vma
->vm_flags
& VM_GROWSDOWN
)
193 if (vma
->vm_flags
& VM_WRITE
)
195 if (vma
->vm_flags
& VM_EXEC
) {
197 if (vma
->vm_flags
& VM_EXECUTABLE
)
202 buffer
+= sprintf(buffer
,
210 mm
->total_vm
<< (PAGE_SHIFT
-10),
211 mm
->locked_vm
<< (PAGE_SHIFT
-10),
212 mm
->rss
<< (PAGE_SHIFT
-10),
219 static void collect_sigign_sigcatch(struct task_struct
*p
, sigset_t
*ign
,
222 struct k_sigaction
*k
;
230 for (i
= 1; i
<= _NSIG
; ++i
, ++k
) {
231 if (k
->sa
.sa_handler
== SIG_IGN
)
233 else if (k
->sa
.sa_handler
!= SIG_DFL
)
239 static inline char * task_sig(struct task_struct
*p
, char *buffer
)
243 buffer
+= sprintf(buffer
, "SigPnd:\t");
244 buffer
= render_sigset_t(&p
->pending
.signal
, buffer
);
246 buffer
+= sprintf(buffer
, "SigBlk:\t");
247 buffer
= render_sigset_t(&p
->blocked
, buffer
);
250 collect_sigign_sigcatch(p
, &ign
, &catch);
251 buffer
+= sprintf(buffer
, "SigIgn:\t");
252 buffer
= render_sigset_t(&ign
, buffer
);
254 buffer
+= sprintf(buffer
, "SigCgt:\t"); /* Linux 2.0 uses "SigCgt" */
255 buffer
= render_sigset_t(&catch, buffer
);
261 extern inline char *task_cap(struct task_struct
*p
, char *buffer
)
263 return buffer
+ sprintf(buffer
, "CapInh:\t%016x\n"
266 cap_t(p
->cap_inheritable
),
267 cap_t(p
->cap_permitted
),
268 cap_t(p
->cap_effective
));
272 int proc_pid_status(struct task_struct
*task
, char * buffer
)
274 char * orig
= buffer
;
275 struct mm_struct
*mm
;
276 #if defined(CONFIG_ARCH_S390)
280 buffer
= task_name(task
, buffer
);
281 buffer
= task_state(task
, buffer
);
285 atomic_inc(&mm
->mm_users
);
288 buffer
= task_mem(mm
, buffer
);
291 buffer
= task_sig(task
, buffer
);
292 buffer
= task_cap(task
, buffer
);
293 #if defined(CONFIG_ARCH_S390)
294 for(line
=0;(len
=sprintf_regs(line
,buffer
,task
,NULL
,NULL
))!=0;line
++)
297 return buffer
- orig
;
300 int proc_pid_stat(struct task_struct
*task
, char * buffer
)
302 unsigned long vsize
, eip
, esp
, wchan
;
304 int tty_pgrp
= -1, tty_nr
= 0;
305 sigset_t sigign
, sigcatch
;
309 struct mm_struct
*mm
;
311 state
= *get_task_state(task
);
312 vsize
= eip
= esp
= 0;
316 atomic_inc(&mm
->mm_users
);
318 tty_pgrp
= task
->tty
->pgrp
;
319 tty_nr
= kdev_t_to_nr(task
->tty
->device
);
323 struct vm_area_struct
*vma
;
327 vsize
+= vma
->vm_end
- vma
->vm_start
;
330 eip
= KSTK_EIP(task
);
331 esp
= KSTK_ESP(task
);
335 wchan
= get_wchan(task
);
337 collect_sigign_sigcatch(task
, &sigign
, &sigcatch
);
339 /* scale priority and nice values from timeslices to -20..20 */
340 /* to make it look like a "normal" Unix priority/nice value */
341 priority
= task
->counter
;
342 priority
= 20 - (priority
* 10 + DEF_COUNTER
/ 2) / DEF_COUNTER
;
345 read_lock(&tasklist_lock
);
346 ppid
= task
->p_opptr
->pid
;
347 read_unlock(&tasklist_lock
);
348 res
= sprintf(buffer
,"%d (%s) %c %d %d %d %d %d %lu %lu \
349 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
350 %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
364 task
->times
.tms_utime
,
365 task
->times
.tms_stime
,
366 task
->times
.tms_cutime
,
367 task
->times
.tms_cstime
,
374 mm
? mm
->rss
: 0, /* you might want to shift this left 3 */
375 task
->rlim
? task
->rlim
[RLIMIT_RSS
].rlim_cur
: 0,
376 mm
? mm
->start_code
: 0,
377 mm
? mm
->end_code
: 0,
378 mm
? mm
->start_stack
: 0,
381 /* The signal information here is obsolete.
382 * It must be decimal for Linux 2.0 compatibility.
383 * Use /proc/#/status for real-time signals.
385 task
->pending
.signal
.sig
[0] & 0x7fffffffUL
,
386 task
->blocked
.sig
[0] & 0x7fffffffUL
,
387 sigign
.sig
[0] & 0x7fffffffUL
,
388 sigcatch
.sig
[0] & 0x7fffffffUL
,
399 static inline void statm_pte_range(pmd_t
* pmd
, unsigned long address
, unsigned long size
,
400 int * pages
, int * shared
, int * dirty
, int * total
)
412 pte
= pte_offset(pmd
, address
);
413 address
&= ~PMD_MASK
;
414 end
= address
+ size
;
421 address
+= PAGE_SIZE
;
426 if (!pte_present(page
))
431 ptpage
= pte_page(page
);
432 if ((!VALID_PAGE(ptpage
)) ||
433 PageReserved(ptpage
))
435 if (page_count(pte_page(page
)) > 1)
437 } while (address
< end
);
440 static inline void statm_pmd_range(pgd_t
* pgd
, unsigned long address
, unsigned long size
,
441 int * pages
, int * shared
, int * dirty
, int * total
)
453 pmd
= pmd_offset(pgd
, address
);
454 address
&= ~PGDIR_MASK
;
455 end
= address
+ size
;
456 if (end
> PGDIR_SIZE
)
459 statm_pte_range(pmd
, address
, end
- address
, pages
, shared
, dirty
, total
);
460 address
= (address
+ PMD_SIZE
) & PMD_MASK
;
462 } while (address
< end
);
465 static void statm_pgd_range(pgd_t
* pgd
, unsigned long address
, unsigned long end
,
466 int * pages
, int * shared
, int * dirty
, int * total
)
468 while (address
< end
) {
469 statm_pmd_range(pgd
, address
, end
- address
, pages
, shared
, dirty
, total
);
470 address
= (address
+ PGDIR_SIZE
) & PGDIR_MASK
;
475 int proc_pid_statm(struct task_struct
*task
, char * buffer
)
477 struct mm_struct
*mm
;
478 int size
=0, resident
=0, share
=0, trs
=0, lrs
=0, drs
=0, dt
=0;
483 atomic_inc(&mm
->mm_users
);
486 struct vm_area_struct
* vma
;
490 pgd_t
*pgd
= pgd_offset(mm
, vma
->vm_start
);
491 int pages
= 0, shared
= 0, dirty
= 0, total
= 0;
493 statm_pgd_range(pgd
, vma
->vm_start
, vma
->vm_end
, &pages
, &shared
, &dirty
, &total
);
498 if (vma
->vm_flags
& VM_EXECUTABLE
)
499 trs
+= pages
; /* text */
500 else if (vma
->vm_flags
& VM_GROWSDOWN
)
501 drs
+= pages
; /* stack */
502 else if (vma
->vm_end
> 0x60000000)
503 lrs
+= pages
; /* library */
511 return sprintf(buffer
,"%d %d %d %d %d %d %d\n",
512 size
, resident
, share
, trs
, lrs
, drs
, dt
);
516 * The way we support synthetic files > 4K
517 * - without storing their contents in some buffer and
518 * - without walking through the entire synthetic file until we reach the
519 * position of the requested data
520 * is to cleverly encode the current position in the file's f_pos field.
521 * There is no requirement that a read() call which returns `count' bytes
522 * of data increases f_pos by exactly `count'.
524 * This idea is Linus' one. Bruno implemented it.
528 * For the /proc/<pid>/maps file, we use fixed length records, each containing
531 #define MAPS_LINE_LENGTH 4096
532 #define MAPS_LINE_SHIFT 12
534 * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
535 * + (index into the line)
537 /* for systems with sizeof(void*) == 4: */
538 #define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu"
539 #define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
541 /* for systems with sizeof(void*) == 8: */
542 #define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu"
543 #define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
545 #define MAPS_LINE_MAX MAPS_LINE_MAX8
548 ssize_t
proc_pid_read_maps (struct task_struct
*task
, struct file
* file
, char * buf
,
549 size_t count
, loff_t
*ppos
)
551 struct mm_struct
*mm
;
552 struct vm_area_struct
* map
, * next
;
553 char * destptr
= buf
, * buffer
;
560 * We might sleep getting the page, so get it first.
563 buffer
= (char*)__get_free_page(GFP_KERNEL
);
572 atomic_inc(&mm
->mm_users
);
577 /* Check whether the mmaps could change if we sleep */
578 volatile_task
= (task
!= current
|| atomic_read(&mm
->mm_users
) > 1);
581 lineno
= *ppos
>> MAPS_LINE_SHIFT
;
582 column
= *ppos
& (MAPS_LINE_LENGTH
-1);
584 /* quickly go to line lineno */
586 for (map
= mm
->mmap
, i
= 0; map
&& (i
< lineno
); map
= map
->vm_next
, i
++)
589 for ( ; map
; map
= next
) {
590 /* produce the next line */
592 char str
[5], *cp
= str
;
596 int maxlen
= (sizeof(void*) == 4) ?
597 MAPS_LINE_MAX4
: MAPS_LINE_MAX8
;
601 * Get the next vma now (but it won't be used if we sleep).
604 flags
= map
->vm_flags
;
606 *cp
++ = flags
& VM_READ
? 'r' : '-';
607 *cp
++ = flags
& VM_WRITE
? 'w' : '-';
608 *cp
++ = flags
& VM_EXEC
? 'x' : '-';
609 *cp
++ = flags
& VM_MAYSHARE
? 's' : 'p';
614 if (map
->vm_file
!= NULL
) {
615 dev
= map
->vm_file
->f_dentry
->d_inode
->i_dev
;
616 ino
= map
->vm_file
->f_dentry
->d_inode
->i_ino
;
617 line
= d_path(map
->vm_file
->f_dentry
,
618 map
->vm_file
->f_vfsmnt
,
620 buffer
[PAGE_SIZE
-1] = '\n';
628 sizeof(void*) == 4 ? MAPS_LINE_FORMAT4
: MAPS_LINE_FORMAT8
,
629 map
->vm_start
, map
->vm_end
, str
, map
->vm_pgoff
<< PAGE_SHIFT
,
633 for(i
= len
; i
< maxlen
; i
++)
635 len
= buffer
+ PAGE_SIZE
- line
;
639 column
= 0; /* continue with next line at column 0 */
641 continue; /* we haven't slept */
648 copy_to_user(destptr
, line
+column
, i
); /* may have slept */
654 column
= 0; /* next time: next line at column 0 */
662 /* By writing to user space, we might have slept.
663 * Stop the loop, to avoid a race condition.
671 *ppos
= (lineno
<< MAPS_LINE_SHIFT
) + column
;
675 retval
= destptr
- buf
;
676 free_page((unsigned long)buffer
);
682 int proc_pid_cpu(struct task_struct
*task
, char * buffer
)
686 len
= sprintf(buffer
,
688 task
->times
.tms_utime
,
689 task
->times
.tms_stime
);
691 for (i
= 0 ; i
< smp_num_cpus
; i
++)
692 len
+= sprintf(buffer
+ len
, "cpu%d %lu %lu\n",
694 task
->per_cpu_utime
[cpu_logical_map(i
)],
695 task
->per_cpu_stime
[cpu_logical_map(i
)]);