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_COUNTER
/ 2) / DEF_COUNTER
;
350 read_lock(&tasklist_lock
);
351 ppid
= task
->p_opptr
->pid
;
352 read_unlock(&tasklist_lock
);
353 res
= sprintf(buffer
,"%d (%s) %c %d %d %d %d %d %lu %lu \
354 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
355 %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
369 hz_to_std(task
->times
.tms_utime
),
370 hz_to_std(task
->times
.tms_stime
),
371 hz_to_std(task
->times
.tms_cutime
),
372 hz_to_std(task
->times
.tms_cstime
),
379 mm
? mm
->rss
: 0, /* you might want to shift this left 3 */
380 task
->rlim
? task
->rlim
[RLIMIT_RSS
].rlim_cur
: 0,
381 mm
? mm
->start_code
: 0,
382 mm
? mm
->end_code
: 0,
383 mm
? mm
->start_stack
: 0,
386 /* The signal information here is obsolete.
387 * It must be decimal for Linux 2.0 compatibility.
388 * Use /proc/#/status for real-time signals.
390 task
->signal
.sig
[0] & 0x7fffffffUL
,
391 task
->blocked
.sig
[0] & 0x7fffffffUL
,
392 sigign
.sig
[0] & 0x7fffffffUL
,
393 sigcatch
.sig
[0] & 0x7fffffffUL
,
404 static inline void statm_pte_range(pmd_t
* pmd
, unsigned long address
, unsigned long size
,
405 int * pages
, int * shared
, int * dirty
, int * total
)
417 pte
= pte_offset(pmd
, address
);
418 address
&= ~PMD_MASK
;
419 end
= address
+ size
;
425 address
+= PAGE_SIZE
;
430 if (!pte_present(page
))
435 if ((pte_pagenr(page
) >= max_mapnr
) ||
436 PageReserved(pte_pagenr(page
) + mem_map
))
438 if (page_count(pte_page(page
)) > 1)
440 } while (address
< end
);
443 static inline void statm_pmd_range(pgd_t
* pgd
, unsigned long address
, unsigned long size
,
444 int * pages
, int * shared
, int * dirty
, int * total
)
456 pmd
= pmd_offset(pgd
, address
);
457 address
&= ~PGDIR_MASK
;
458 end
= address
+ size
;
459 if (end
> PGDIR_SIZE
)
462 statm_pte_range(pmd
, address
, end
- address
, pages
, shared
, dirty
, total
);
463 address
= (address
+ PMD_SIZE
) & PMD_MASK
;
465 } while (address
< end
);
468 static void statm_pgd_range(pgd_t
* pgd
, unsigned long address
, unsigned long end
,
469 int * pages
, int * shared
, int * dirty
, int * total
)
471 while (address
< end
) {
472 statm_pmd_range(pgd
, address
, end
- address
, pages
, shared
, dirty
, total
);
473 address
= (address
+ PGDIR_SIZE
) & PGDIR_MASK
;
478 int proc_pid_statm(struct task_struct
*task
, char * buffer
)
480 struct mm_struct
*mm
;
481 int size
=0, resident
=0, share
=0, trs
=0, lrs
=0, drs
=0, dt
=0;
486 atomic_inc(&mm
->mm_users
);
489 struct vm_area_struct
* vma
;
493 pgd_t
*pgd
= pgd_offset(mm
, vma
->vm_start
);
494 int pages
= 0, shared
= 0, dirty
= 0, total
= 0;
496 statm_pgd_range(pgd
, vma
->vm_start
, vma
->vm_end
, &pages
, &shared
, &dirty
, &total
);
501 if (vma
->vm_flags
& VM_EXECUTABLE
)
502 trs
+= pages
; /* text */
503 else if (vma
->vm_flags
& VM_GROWSDOWN
)
504 drs
+= pages
; /* stack */
505 else if (vma
->vm_end
> 0x60000000)
506 lrs
+= pages
; /* library */
514 return sprintf(buffer
,"%d %d %d %d %d %d %d\n",
515 size
, resident
, share
, trs
, lrs
, drs
, dt
);
519 * The way we support synthetic files > 4K
520 * - without storing their contents in some buffer and
521 * - without walking through the entire synthetic file until we reach the
522 * position of the requested data
523 * is to cleverly encode the current position in the file's f_pos field.
524 * There is no requirement that a read() call which returns `count' bytes
525 * of data increases f_pos by exactly `count'.
527 * This idea is Linus' one. Bruno implemented it.
531 * For the /proc/<pid>/maps file, we use fixed length records, each containing
534 #define MAPS_LINE_LENGTH 4096
535 #define MAPS_LINE_SHIFT 12
537 * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
538 * + (index into the line)
540 /* for systems with sizeof(void*) == 4: */
541 #define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu"
542 #define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
544 /* for systems with sizeof(void*) == 8: */
545 #define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu"
546 #define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
548 #define MAPS_LINE_MAX MAPS_LINE_MAX8
551 ssize_t
proc_pid_read_maps (struct task_struct
*task
, struct file
* file
, char * buf
,
552 size_t count
, loff_t
*ppos
)
554 struct mm_struct
*mm
;
555 struct vm_area_struct
* map
, * next
;
556 char * destptr
= buf
, * buffer
;
563 * We might sleep getting the page, so get it first.
566 buffer
= (char*)__get_free_page(GFP_KERNEL
);
575 atomic_inc(&mm
->mm_users
);
580 /* Check whether the mmaps could change if we sleep */
581 volatile_task
= (task
!= current
|| atomic_read(&mm
->mm_users
) > 1);
584 lineno
= *ppos
>> MAPS_LINE_SHIFT
;
585 column
= *ppos
& (MAPS_LINE_LENGTH
-1);
587 /* quickly go to line lineno */
589 for (map
= mm
->mmap
, i
= 0; map
&& (i
< lineno
); map
= map
->vm_next
, i
++)
592 for ( ; map
; map
= next
) {
593 /* produce the next line */
595 char str
[5], *cp
= str
;
599 int maxlen
= (sizeof(void*) == 4) ?
600 MAPS_LINE_MAX4
: MAPS_LINE_MAX8
;
604 * Get the next vma now (but it won't be used if we sleep).
607 flags
= map
->vm_flags
;
609 *cp
++ = flags
& VM_READ
? 'r' : '-';
610 *cp
++ = flags
& VM_WRITE
? 'w' : '-';
611 *cp
++ = flags
& VM_EXEC
? 'x' : '-';
612 *cp
++ = flags
& VM_MAYSHARE
? 's' : 'p';
617 if (map
->vm_file
!= NULL
) {
618 dev
= map
->vm_file
->f_dentry
->d_inode
->i_dev
;
619 ino
= map
->vm_file
->f_dentry
->d_inode
->i_ino
;
620 line
= d_path(map
->vm_file
->f_dentry
,
621 map
->vm_file
->f_vfsmnt
,
623 buffer
[PAGE_SIZE
-1] = '\n';
631 sizeof(void*) == 4 ? MAPS_LINE_FORMAT4
: MAPS_LINE_FORMAT8
,
632 map
->vm_start
, map
->vm_end
, str
, map
->vm_pgoff
<< PAGE_SHIFT
,
636 for(i
= len
; i
< maxlen
; i
++)
638 len
= buffer
+ PAGE_SIZE
- line
;
642 column
= 0; /* continue with next line at column 0 */
644 continue; /* we haven't slept */
651 copy_to_user(destptr
, line
+column
, i
); /* may have slept */
657 column
= 0; /* next time: next line at column 0 */
665 /* By writing to user space, we might have slept.
666 * Stop the loop, to avoid a race condition.
674 *ppos
= (lineno
<< MAPS_LINE_SHIFT
) + column
;
678 retval
= destptr
- buf
;
679 free_page((unsigned long)buffer
);
685 int proc_pid_cpu(struct task_struct
*task
, char * buffer
)
689 len
= sprintf(buffer
,
691 hz_to_std(task
->times
.tms_utime
),
692 hz_to_std(task
->times
.tms_stime
));
694 for (i
= 0 ; i
< smp_num_cpus
; i
++)
695 len
+= sprintf(buffer
+ len
, "cpu%d %lu %lu\n",
697 hz_to_std(task
->per_cpu_utime
[cpu_logical_map(i
)]),
698 hz_to_std(task
->per_cpu_stime
[cpu_logical_map(i
)]));