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
->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
;
305 sigset_t sigign
, sigcatch
;
310 struct mm_struct
*mm
;
312 state
= *get_task_state(task
);
313 vsize
= eip
= esp
= 0;
317 atomic_inc(&mm
->mm_users
);
320 struct vm_area_struct
*vma
;
324 vsize
+= vma
->vm_end
- vma
->vm_start
;
327 eip
= KSTK_EIP(task
);
328 esp
= KSTK_ESP(task
);
332 wchan
= get_wchan(task
);
334 collect_sigign_sigcatch(task
, &sigign
, &sigcatch
);
338 tty_pgrp
= task
->tty
->pgrp
;
341 tty_nr
= task
->tty
? kdev_t_to_nr(task
->tty
->device
) : 0;
344 /* scale priority and nice values from timeslices to -20..20 */
345 /* to make it look like a "normal" Unix priority/nice value */
346 priority
= task
->counter
;
347 priority
= 20 - (priority
* 10 + DEF_PRIORITY
/ 2) / DEF_PRIORITY
;
348 nice
= task
->priority
;
349 nice
= 20 - (nice
* 20 + DEF_PRIORITY
/ 2) / DEF_PRIORITY
;
351 read_lock(&tasklist_lock
);
352 ppid
= task
->p_opptr
->pid
;
353 read_unlock(&tasklist_lock
);
354 res
= sprintf(buffer
,"%d (%s) %c %d %d %d %d %d %lu %lu \
355 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
356 %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
370 task
->times
.tms_utime
,
371 task
->times
.tms_stime
,
372 task
->times
.tms_cutime
,
373 task
->times
.tms_cstime
,
380 mm
? mm
->rss
: 0, /* you might want to shift this left 3 */
381 task
->rlim
? task
->rlim
[RLIMIT_RSS
].rlim_cur
: 0,
382 mm
? mm
->start_code
: 0,
383 mm
? mm
->end_code
: 0,
384 mm
? mm
->start_stack
: 0,
387 /* The signal information here is obsolete.
388 * It must be decimal for Linux 2.0 compatibility.
389 * Use /proc/#/status for real-time signals.
391 task
->signal
.sig
[0] & 0x7fffffffUL
,
392 task
->blocked
.sig
[0] & 0x7fffffffUL
,
393 sigign
.sig
[0] & 0x7fffffffUL
,
394 sigcatch
.sig
[0] & 0x7fffffffUL
,
405 static inline void statm_pte_range(pmd_t
* pmd
, unsigned long address
, unsigned long size
,
406 int * pages
, int * shared
, int * dirty
, int * total
)
418 pte
= pte_offset(pmd
, address
);
419 address
&= ~PMD_MASK
;
420 end
= address
+ size
;
426 address
+= PAGE_SIZE
;
431 if (!pte_present(page
))
436 if ((pte_pagenr(page
) >= max_mapnr
) ||
437 PageReserved(pte_pagenr(page
) + mem_map
))
439 if (page_count(pte_page(page
)) > 1)
441 } while (address
< end
);
444 static inline void statm_pmd_range(pgd_t
* pgd
, unsigned long address
, unsigned long size
,
445 int * pages
, int * shared
, int * dirty
, int * total
)
457 pmd
= pmd_offset(pgd
, address
);
458 address
&= ~PGDIR_MASK
;
459 end
= address
+ size
;
460 if (end
> PGDIR_SIZE
)
463 statm_pte_range(pmd
, address
, end
- address
, pages
, shared
, dirty
, total
);
464 address
= (address
+ PMD_SIZE
) & PMD_MASK
;
466 } while (address
< end
);
469 static void statm_pgd_range(pgd_t
* pgd
, unsigned long address
, unsigned long end
,
470 int * pages
, int * shared
, int * dirty
, int * total
)
472 while (address
< end
) {
473 statm_pmd_range(pgd
, address
, end
- address
, pages
, shared
, dirty
, total
);
474 address
= (address
+ PGDIR_SIZE
) & PGDIR_MASK
;
479 int proc_pid_statm(struct task_struct
*task
, char * buffer
)
481 struct mm_struct
*mm
;
482 int size
=0, resident
=0, share
=0, trs
=0, lrs
=0, drs
=0, dt
=0;
487 atomic_inc(&mm
->mm_users
);
490 struct vm_area_struct
* vma
;
494 pgd_t
*pgd
= pgd_offset(mm
, vma
->vm_start
);
495 int pages
= 0, shared
= 0, dirty
= 0, total
= 0;
497 statm_pgd_range(pgd
, vma
->vm_start
, vma
->vm_end
, &pages
, &shared
, &dirty
, &total
);
502 if (vma
->vm_flags
& VM_EXECUTABLE
)
503 trs
+= pages
; /* text */
504 else if (vma
->vm_flags
& VM_GROWSDOWN
)
505 drs
+= pages
; /* stack */
506 else if (vma
->vm_end
> 0x60000000)
507 lrs
+= pages
; /* library */
515 return sprintf(buffer
,"%d %d %d %d %d %d %d\n",
516 size
, resident
, share
, trs
, lrs
, drs
, dt
);
520 * The way we support synthetic files > 4K
521 * - without storing their contents in some buffer and
522 * - without walking through the entire synthetic file until we reach the
523 * position of the requested data
524 * is to cleverly encode the current position in the file's f_pos field.
525 * There is no requirement that a read() call which returns `count' bytes
526 * of data increases f_pos by exactly `count'.
528 * This idea is Linus' one. Bruno implemented it.
532 * For the /proc/<pid>/maps file, we use fixed length records, each containing
535 #define MAPS_LINE_LENGTH 4096
536 #define MAPS_LINE_SHIFT 12
538 * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
539 * + (index into the line)
541 /* for systems with sizeof(void*) == 4: */
542 #define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu"
543 #define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
545 /* for systems with sizeof(void*) == 8: */
546 #define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu"
547 #define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
549 #define MAPS_LINE_MAX MAPS_LINE_MAX8
552 ssize_t
proc_pid_read_maps (struct task_struct
*task
, struct file
* file
, char * buf
,
553 size_t count
, loff_t
*ppos
)
555 struct mm_struct
*mm
;
556 struct vm_area_struct
* map
, * next
;
557 char * destptr
= buf
, * buffer
;
564 * We might sleep getting the page, so get it first.
567 buffer
= (char*)__get_free_page(GFP_KERNEL
);
576 atomic_inc(&mm
->mm_users
);
581 /* Check whether the mmaps could change if we sleep */
582 volatile_task
= (task
!= current
|| atomic_read(&mm
->mm_users
) > 1);
585 lineno
= *ppos
>> MAPS_LINE_SHIFT
;
586 column
= *ppos
& (MAPS_LINE_LENGTH
-1);
588 /* quickly go to line lineno */
590 for (map
= mm
->mmap
, i
= 0; map
&& (i
< lineno
); map
= map
->vm_next
, i
++)
593 for ( ; map
; map
= next
) {
594 /* produce the next line */
596 char str
[5], *cp
= str
;
600 int maxlen
= (sizeof(void*) == 4) ?
601 MAPS_LINE_MAX4
: MAPS_LINE_MAX8
;
605 * Get the next vma now (but it won't be used if we sleep).
608 flags
= map
->vm_flags
;
610 *cp
++ = flags
& VM_READ
? 'r' : '-';
611 *cp
++ = flags
& VM_WRITE
? 'w' : '-';
612 *cp
++ = flags
& VM_EXEC
? 'x' : '-';
613 *cp
++ = flags
& VM_MAYSHARE
? 's' : 'p';
618 if (map
->vm_file
!= NULL
) {
619 dev
= map
->vm_file
->f_dentry
->d_inode
->i_dev
;
620 ino
= map
->vm_file
->f_dentry
->d_inode
->i_ino
;
621 line
= d_path(map
->vm_file
->f_dentry
,
622 map
->vm_file
->f_vfsmnt
,
624 buffer
[PAGE_SIZE
-1] = '\n';
632 sizeof(void*) == 4 ? MAPS_LINE_FORMAT4
: MAPS_LINE_FORMAT8
,
633 map
->vm_start
, map
->vm_end
, str
, map
->vm_pgoff
<< PAGE_SHIFT
,
637 for(i
= len
; i
< maxlen
; i
++)
639 len
= buffer
+ PAGE_SIZE
- line
;
643 column
= 0; /* continue with next line at column 0 */
645 continue; /* we haven't slept */
652 copy_to_user(destptr
, line
+column
, i
); /* may have slept */
658 column
= 0; /* next time: next line at column 0 */
666 /* By writing to user space, we might have slept.
667 * Stop the loop, to avoid a race condition.
675 *ppos
= (lineno
<< MAPS_LINE_SHIFT
) + column
;
679 retval
= destptr
- buf
;
680 free_page((unsigned long)buffer
);
686 int proc_pid_cpu(struct task_struct
*task
, char * buffer
)
690 len
= sprintf(buffer
,
692 task
->times
.tms_utime
,
693 task
->times
.tms_stime
);
695 for (i
= 0 ; i
< smp_num_cpus
; i
++)
696 len
+= sprintf(buffer
+ len
, "cpu%d %lu %lu\n",
698 task
->per_cpu_utime
[cpu_logical_map(i
)],
699 task
->per_cpu_stime
[cpu_logical_map(i
)]);