aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSiddhesh Poyarekar <siddhesh.poyarekar@gmail.com>2012-03-21 19:34:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-21 20:54:58 -0400
commitb76437579d1344b612cf1851ae610c636cec7db0 (patch)
tree37c31c957f1159635258168e27e49b90347e37aa
parent9e81130b7ce23050335b1197bb51743517b5b9d0 (diff)
procfs: mark thread stack correctly in proc/<pid>/maps
Stack for a new thread is mapped by userspace code and passed via sys_clone. This memory is currently seen as anonymous in /proc/<pid>/maps, which makes it difficult to ascertain which mappings are being used for thread stacks. This patch uses the individual task stack pointers to determine which vmas are actually thread stacks. For a multithreaded program like the following: #include <pthread.h> void *thread_main(void *foo) { while(1); } int main() { pthread_t t; pthread_create(&t, NULL, thread_main, NULL); pthread_join(t, NULL); } proc/PID/maps looks like the following: 00400000-00401000 r-xp 00000000 fd:0a 3671804 /home/siddhesh/a.out 00600000-00601000 rw-p 00000000 fd:0a 3671804 /home/siddhesh/a.out 019ef000-01a10000 rw-p 00000000 00:00 0 [heap] 7f8a44491000-7f8a44492000 ---p 00000000 00:00 0 7f8a44492000-7f8a44c92000 rw-p 00000000 00:00 0 7f8a44c92000-7f8a44e3d000 r-xp 00000000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a44e3d000-7f8a4503d000 ---p 001ab000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a4503d000-7f8a45041000 r--p 001ab000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a45041000-7f8a45043000 rw-p 001af000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a45043000-7f8a45048000 rw-p 00000000 00:00 0 7f8a45048000-7f8a4505f000 r-xp 00000000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4505f000-7f8a4525e000 ---p 00017000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4525e000-7f8a4525f000 r--p 00016000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4525f000-7f8a45260000 rw-p 00017000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a45260000-7f8a45264000 rw-p 00000000 00:00 0 7f8a45264000-7f8a45286000 r-xp 00000000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45457000-7f8a4545a000 rw-p 00000000 00:00 0 7f8a45484000-7f8a45485000 rw-p 00000000 00:00 0 7f8a45485000-7f8a45486000 r--p 00021000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45486000-7f8a45487000 rw-p 00022000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45487000-7f8a45488000 rw-p 00000000 00:00 0 7fff6273b000-7fff6275c000 rw-p 00000000 00:00 0 [stack] 7fff627ff000-7fff62800000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Here, one could guess that 7f8a44492000-7f8a44c92000 is a stack since the earlier vma that has no permissions (7f8a44e3d000-7f8a4503d000) but that is not always a reliable way to find out which vma is a thread stack. Also, /proc/PID/maps and /proc/PID/task/TID/maps has the same content. With this patch in place, /proc/PID/task/TID/maps are treated as 'maps as the task would see it' and hence, only the vma that that task uses as stack is marked as [stack]. All other 'stack' vmas are marked as anonymous memory. /proc/PID/maps acts as a thread group level view, where all thread stack vmas are marked as [stack:TID] where TID is the process ID of the task that uses that vma as stack, while the process stack is marked as [stack]. So /proc/PID/maps will look like this: 00400000-00401000 r-xp 00000000 fd:0a 3671804 /home/siddhesh/a.out 00600000-00601000 rw-p 00000000 fd:0a 3671804 /home/siddhesh/a.out 019ef000-01a10000 rw-p 00000000 00:00 0 [heap] 7f8a44491000-7f8a44492000 ---p 00000000 00:00 0 7f8a44492000-7f8a44c92000 rw-p 00000000 00:00 0 [stack:1442] 7f8a44c92000-7f8a44e3d000 r-xp 00000000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a44e3d000-7f8a4503d000 ---p 001ab000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a4503d000-7f8a45041000 r--p 001ab000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a45041000-7f8a45043000 rw-p 001af000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a45043000-7f8a45048000 rw-p 00000000 00:00 0 7f8a45048000-7f8a4505f000 r-xp 00000000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4505f000-7f8a4525e000 ---p 00017000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4525e000-7f8a4525f000 r--p 00016000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4525f000-7f8a45260000 rw-p 00017000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a45260000-7f8a45264000 rw-p 00000000 00:00 0 7f8a45264000-7f8a45286000 r-xp 00000000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45457000-7f8a4545a000 rw-p 00000000 00:00 0 7f8a45484000-7f8a45485000 rw-p 00000000 00:00 0 7f8a45485000-7f8a45486000 r--p 00021000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45486000-7f8a45487000 rw-p 00022000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45487000-7f8a45488000 rw-p 00000000 00:00 0 7fff6273b000-7fff6275c000 rw-p 00000000 00:00 0 [stack] 7fff627ff000-7fff62800000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Thus marking all vmas that are used as stacks by the threads in the thread group along with the process stack. The task level maps will however like this: 00400000-00401000 r-xp 00000000 fd:0a 3671804 /home/siddhesh/a.out 00600000-00601000 rw-p 00000000 fd:0a 3671804 /home/siddhesh/a.out 019ef000-01a10000 rw-p 00000000 00:00 0 [heap] 7f8a44491000-7f8a44492000 ---p 00000000 00:00 0 7f8a44492000-7f8a44c92000 rw-p 00000000 00:00 0 [stack] 7f8a44c92000-7f8a44e3d000 r-xp 00000000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a44e3d000-7f8a4503d000 ---p 001ab000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a4503d000-7f8a45041000 r--p 001ab000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a45041000-7f8a45043000 rw-p 001af000 fd:00 2097482 /lib64/libc-2.14.90.so 7f8a45043000-7f8a45048000 rw-p 00000000 00:00 0 7f8a45048000-7f8a4505f000 r-xp 00000000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4505f000-7f8a4525e000 ---p 00017000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4525e000-7f8a4525f000 r--p 00016000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a4525f000-7f8a45260000 rw-p 00017000 fd:00 2099938 /lib64/libpthread-2.14.90.so 7f8a45260000-7f8a45264000 rw-p 00000000 00:00 0 7f8a45264000-7f8a45286000 r-xp 00000000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45457000-7f8a4545a000 rw-p 00000000 00:00 0 7f8a45484000-7f8a45485000 rw-p 00000000 00:00 0 7f8a45485000-7f8a45486000 r--p 00021000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45486000-7f8a45487000 rw-p 00022000 fd:00 2097348 /lib64/ld-2.14.90.so 7f8a45487000-7f8a45488000 rw-p 00000000 00:00 0 7fff6273b000-7fff6275c000 rw-p 00000000 00:00 0 7fff627ff000-7fff62800000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] where only the vma that is being used as a stack by *that* task is marked as [stack]. Analogous changes have been made to /proc/PID/smaps, /proc/PID/numa_maps, /proc/PID/task/TID/smaps and /proc/PID/task/TID/numa_maps. Relevant snippets from smaps and numa_maps: [siddhesh@localhost ~ ]$ pgrep a.out 1441 [siddhesh@localhost ~ ]$ cat /proc/1441/smaps | grep "\[stack" 7f8a44492000-7f8a44c92000 rw-p 00000000 00:00 0 [stack:1442] 7fff6273b000-7fff6275c000 rw-p 00000000 00:00 0 [stack] [siddhesh@localhost ~ ]$ cat /proc/1441/task/1442/smaps | grep "\[stack" 7f8a44492000-7f8a44c92000 rw-p 00000000 00:00 0 [stack] [siddhesh@localhost ~ ]$ cat /proc/1441/task/1441/smaps | grep "\[stack" 7fff6273b000-7fff6275c000 rw-p 00000000 00:00 0 [stack] [siddhesh@localhost ~ ]$ cat /proc/1441/numa_maps | grep "stack" 7f8a44492000 default stack:1442 anon=2 dirty=2 N0=2 7fff6273a000 default stack anon=3 dirty=3 N0=3 [siddhesh@localhost ~ ]$ cat /proc/1441/task/1442/numa_maps | grep "stack" 7f8a44492000 default stack anon=2 dirty=2 N0=2 [siddhesh@localhost ~ ]$ cat /proc/1441/task/1441/numa_maps | grep "stack" 7fff6273a000 default stack anon=3 dirty=3 N0=3 [akpm@linux-foundation.org: checkpatch fixes] [akpm@linux-foundation.org: fix build] Signed-off-by: Siddhesh Poyarekar <siddhesh.poyarekar@gmail.com> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Jamie Lokier <jamie@shareable.org> Cc: Mike Frysinger <vapier@gentoo.org> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Matt Mackall <mpm@selenic.com> Cc: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/filesystems/proc.txt32
-rw-r--r--fs/proc/base.c12
-rw-r--r--fs/proc/internal.h9
-rw-r--r--fs/proc/task_mmu.c210
-rw-r--r--fs/proc/task_nommu.c69
-rw-r--r--include/linux/mm.h3
-rw-r--r--mm/util.c41
7 files changed, 313 insertions, 63 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index a76a26a1db8a..b7413cb46dcb 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -290,7 +290,7 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
290 rsslim current limit in bytes on the rss 290 rsslim current limit in bytes on the rss
291 start_code address above which program text can run 291 start_code address above which program text can run
292 end_code address below which program text can run 292 end_code address below which program text can run
293 start_stack address of the start of the stack 293 start_stack address of the start of the main process stack
294 esp current value of ESP 294 esp current value of ESP
295 eip current value of EIP 295 eip current value of EIP
296 pending bitmap of pending signals 296 pending bitmap of pending signals
@@ -325,7 +325,7 @@ address perms offset dev inode pathname
325a7cb1000-a7cb2000 ---p 00000000 00:00 0 325a7cb1000-a7cb2000 ---p 00000000 00:00 0
326a7cb2000-a7eb2000 rw-p 00000000 00:00 0 326a7cb2000-a7eb2000 rw-p 00000000 00:00 0
327a7eb2000-a7eb3000 ---p 00000000 00:00 0 327a7eb2000-a7eb3000 ---p 00000000 00:00 0
328a7eb3000-a7ed5000 rw-p 00000000 00:00 0 328a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack:1001]
329a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6 329a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6
330a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6 330a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6
331a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6 331a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6
@@ -357,11 +357,39 @@ is not associated with a file:
357 357
358 [heap] = the heap of the program 358 [heap] = the heap of the program
359 [stack] = the stack of the main process 359 [stack] = the stack of the main process
360 [stack:1001] = the stack of the thread with tid 1001
360 [vdso] = the "virtual dynamic shared object", 361 [vdso] = the "virtual dynamic shared object",
361 the kernel system call handler 362 the kernel system call handler
362 363
363 or if empty, the mapping is anonymous. 364 or if empty, the mapping is anonymous.
364 365
366The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
367of the individual tasks of a process. In this file you will see a mapping marked
368as [stack] if that task sees it as a stack. This is a key difference from the
369content of /proc/PID/maps, where you will see all mappings that are being used
370as stack by all of those tasks. Hence, for the example above, the task-level
371map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
372
37308048000-08049000 r-xp 00000000 03:00 8312 /opt/test
37408049000-0804a000 rw-p 00001000 03:00 8312 /opt/test
3750804a000-0806b000 rw-p 00000000 00:00 0 [heap]
376a7cb1000-a7cb2000 ---p 00000000 00:00 0
377a7cb2000-a7eb2000 rw-p 00000000 00:00 0
378a7eb2000-a7eb3000 ---p 00000000 00:00 0
379a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack]
380a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6
381a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6
382a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6
383a800b000-a800e000 rw-p 00000000 00:00 0
384a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0
385a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0
386a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0
387a8024000-a8027000 rw-p 00000000 00:00 0
388a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2
389a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2
390a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2
391aff35000-aff4a000 rw-p 00000000 00:00 0
392ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
365 393
366The /proc/PID/smaps is an extension based on maps, showing the memory 394The /proc/PID/smaps is an extension based on maps, showing the memory
367consumption for each of the process's mappings. For each of mappings there 395consumption for each of the process's mappings. For each of mappings there
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 965d4bde3a3b..3b42c1418f31 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2989,9 +2989,9 @@ static const struct pid_entry tgid_base_stuff[] = {
2989 INF("cmdline", S_IRUGO, proc_pid_cmdline), 2989 INF("cmdline", S_IRUGO, proc_pid_cmdline),
2990 ONE("stat", S_IRUGO, proc_tgid_stat), 2990 ONE("stat", S_IRUGO, proc_tgid_stat),
2991 ONE("statm", S_IRUGO, proc_pid_statm), 2991 ONE("statm", S_IRUGO, proc_pid_statm),
2992 REG("maps", S_IRUGO, proc_maps_operations), 2992 REG("maps", S_IRUGO, proc_pid_maps_operations),
2993#ifdef CONFIG_NUMA 2993#ifdef CONFIG_NUMA
2994 REG("numa_maps", S_IRUGO, proc_numa_maps_operations), 2994 REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations),
2995#endif 2995#endif
2996 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), 2996 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
2997 LNK("cwd", proc_cwd_link), 2997 LNK("cwd", proc_cwd_link),
@@ -3002,7 +3002,7 @@ static const struct pid_entry tgid_base_stuff[] = {
3002 REG("mountstats", S_IRUSR, proc_mountstats_operations), 3002 REG("mountstats", S_IRUSR, proc_mountstats_operations),
3003#ifdef CONFIG_PROC_PAGE_MONITOR 3003#ifdef CONFIG_PROC_PAGE_MONITOR
3004 REG("clear_refs", S_IWUSR, proc_clear_refs_operations), 3004 REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
3005 REG("smaps", S_IRUGO, proc_smaps_operations), 3005 REG("smaps", S_IRUGO, proc_pid_smaps_operations),
3006 REG("pagemap", S_IRUGO, proc_pagemap_operations), 3006 REG("pagemap", S_IRUGO, proc_pagemap_operations),
3007#endif 3007#endif
3008#ifdef CONFIG_SECURITY 3008#ifdef CONFIG_SECURITY
@@ -3348,9 +3348,9 @@ static const struct pid_entry tid_base_stuff[] = {
3348 INF("cmdline", S_IRUGO, proc_pid_cmdline), 3348 INF("cmdline", S_IRUGO, proc_pid_cmdline),
3349 ONE("stat", S_IRUGO, proc_tid_stat), 3349 ONE("stat", S_IRUGO, proc_tid_stat),
3350 ONE("statm", S_IRUGO, proc_pid_statm), 3350 ONE("statm", S_IRUGO, proc_pid_statm),
3351 REG("maps", S_IRUGO, proc_maps_operations), 3351 REG("maps", S_IRUGO, proc_tid_maps_operations),
3352#ifdef CONFIG_NUMA 3352#ifdef CONFIG_NUMA
3353 REG("numa_maps", S_IRUGO, proc_numa_maps_operations), 3353 REG("numa_maps", S_IRUGO, proc_tid_numa_maps_operations),
3354#endif 3354#endif
3355 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), 3355 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
3356 LNK("cwd", proc_cwd_link), 3356 LNK("cwd", proc_cwd_link),
@@ -3360,7 +3360,7 @@ static const struct pid_entry tid_base_stuff[] = {
3360 REG("mountinfo", S_IRUGO, proc_mountinfo_operations), 3360 REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
3361#ifdef CONFIG_PROC_PAGE_MONITOR 3361#ifdef CONFIG_PROC_PAGE_MONITOR
3362 REG("clear_refs", S_IWUSR, proc_clear_refs_operations), 3362 REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
3363 REG("smaps", S_IRUGO, proc_smaps_operations), 3363 REG("smaps", S_IRUGO, proc_tid_smaps_operations),
3364 REG("pagemap", S_IRUGO, proc_pagemap_operations), 3364 REG("pagemap", S_IRUGO, proc_pagemap_operations),
3365#endif 3365#endif
3366#ifdef CONFIG_SECURITY 3366#ifdef CONFIG_SECURITY
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 292577531ad1..c44efe19798f 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -53,9 +53,12 @@ extern int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
53 struct pid *pid, struct task_struct *task); 53 struct pid *pid, struct task_struct *task);
54extern loff_t mem_lseek(struct file *file, loff_t offset, int orig); 54extern loff_t mem_lseek(struct file *file, loff_t offset, int orig);
55 55
56extern const struct file_operations proc_maps_operations; 56extern const struct file_operations proc_pid_maps_operations;
57extern const struct file_operations proc_numa_maps_operations; 57extern const struct file_operations proc_tid_maps_operations;
58extern const struct file_operations proc_smaps_operations; 58extern const struct file_operations proc_pid_numa_maps_operations;
59extern const struct file_operations proc_tid_numa_maps_operations;
60extern const struct file_operations proc_pid_smaps_operations;
61extern const struct file_operations proc_tid_smaps_operations;
59extern const struct file_operations proc_clear_refs_operations; 62extern const struct file_operations proc_clear_refs_operations;
60extern const struct file_operations proc_pagemap_operations; 63extern const struct file_operations proc_pagemap_operations;
61extern const struct file_operations proc_net_operations; 64extern const struct file_operations proc_net_operations;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index c7e3a163295c..9694cc283511 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -209,16 +209,20 @@ static int do_maps_open(struct inode *inode, struct file *file,
209 return ret; 209 return ret;
210} 210}
211 211
212static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) 212static void
213show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
213{ 214{
214 struct mm_struct *mm = vma->vm_mm; 215 struct mm_struct *mm = vma->vm_mm;
215 struct file *file = vma->vm_file; 216 struct file *file = vma->vm_file;
217 struct proc_maps_private *priv = m->private;
218 struct task_struct *task = priv->task;
216 vm_flags_t flags = vma->vm_flags; 219 vm_flags_t flags = vma->vm_flags;
217 unsigned long ino = 0; 220 unsigned long ino = 0;
218 unsigned long long pgoff = 0; 221 unsigned long long pgoff = 0;
219 unsigned long start, end; 222 unsigned long start, end;
220 dev_t dev = 0; 223 dev_t dev = 0;
221 int len; 224 int len;
225 const char *name = NULL;
222 226
223 if (file) { 227 if (file) {
224 struct inode *inode = vma->vm_file->f_path.dentry->d_inode; 228 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
@@ -252,36 +256,57 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
252 if (file) { 256 if (file) {
253 pad_len_spaces(m, len); 257 pad_len_spaces(m, len);
254 seq_path(m, &file->f_path, "\n"); 258 seq_path(m, &file->f_path, "\n");
255 } else { 259 goto done;
256 const char *name = arch_vma_name(vma); 260 }
257 if (!name) { 261
258 if (mm) { 262 name = arch_vma_name(vma);
259 if (vma->vm_start <= mm->brk && 263 if (!name) {
260 vma->vm_end >= mm->start_brk) { 264 pid_t tid;
261 name = "[heap]"; 265
262 } else if (vma->vm_start <= mm->start_stack && 266 if (!mm) {
263 vma->vm_end >= mm->start_stack) { 267 name = "[vdso]";
264 name = "[stack]"; 268 goto done;
265 } 269 }
270
271 if (vma->vm_start <= mm->brk &&
272 vma->vm_end >= mm->start_brk) {
273 name = "[heap]";
274 goto done;
275 }
276
277 tid = vm_is_stack(task, vma, is_pid);
278
279 if (tid != 0) {
280 /*
281 * Thread stack in /proc/PID/task/TID/maps or
282 * the main process stack.
283 */
284 if (!is_pid || (vma->vm_start <= mm->start_stack &&
285 vma->vm_end >= mm->start_stack)) {
286 name = "[stack]";
266 } else { 287 } else {
267 name = "[vdso]"; 288 /* Thread stack in /proc/PID/maps */
289 pad_len_spaces(m, len);
290 seq_printf(m, "[stack:%d]", tid);
268 } 291 }
269 } 292 }
270 if (name) { 293 }
271 pad_len_spaces(m, len); 294
272 seq_puts(m, name); 295done:
273 } 296 if (name) {
297 pad_len_spaces(m, len);
298 seq_puts(m, name);
274 } 299 }
275 seq_putc(m, '\n'); 300 seq_putc(m, '\n');
276} 301}
277 302
278static int show_map(struct seq_file *m, void *v) 303static int show_map(struct seq_file *m, void *v, int is_pid)
279{ 304{
280 struct vm_area_struct *vma = v; 305 struct vm_area_struct *vma = v;
281 struct proc_maps_private *priv = m->private; 306 struct proc_maps_private *priv = m->private;
282 struct task_struct *task = priv->task; 307 struct task_struct *task = priv->task;
283 308
284 show_map_vma(m, vma); 309 show_map_vma(m, vma, is_pid);
285 310
286 if (m->count < m->size) /* vma is copied successfully */ 311 if (m->count < m->size) /* vma is copied successfully */
287 m->version = (vma != get_gate_vma(task->mm)) 312 m->version = (vma != get_gate_vma(task->mm))
@@ -289,20 +314,49 @@ static int show_map(struct seq_file *m, void *v)
289 return 0; 314 return 0;
290} 315}
291 316
317static int show_pid_map(struct seq_file *m, void *v)
318{
319 return show_map(m, v, 1);
320}
321
322static int show_tid_map(struct seq_file *m, void *v)
323{
324 return show_map(m, v, 0);
325}
326
292static const struct seq_operations proc_pid_maps_op = { 327static const struct seq_operations proc_pid_maps_op = {
293 .start = m_start, 328 .start = m_start,
294 .next = m_next, 329 .next = m_next,
295 .stop = m_stop, 330 .stop = m_stop,
296 .show = show_map 331 .show = show_pid_map
332};
333
334static const struct seq_operations proc_tid_maps_op = {
335 .start = m_start,
336 .next = m_next,
337 .stop = m_stop,
338 .show = show_tid_map
297}; 339};
298 340
299static int maps_open(struct inode *inode, struct file *file) 341static int pid_maps_open(struct inode *inode, struct file *file)
300{ 342{
301 return do_maps_open(inode, file, &proc_pid_maps_op); 343 return do_maps_open(inode, file, &proc_pid_maps_op);
302} 344}
303 345
304const struct file_operations proc_maps_operations = { 346static int tid_maps_open(struct inode *inode, struct file *file)
305 .open = maps_open, 347{
348 return do_maps_open(inode, file, &proc_tid_maps_op);
349}
350
351const struct file_operations proc_pid_maps_operations = {
352 .open = pid_maps_open,
353 .read = seq_read,
354 .llseek = seq_lseek,
355 .release = seq_release_private,
356};
357
358const struct file_operations proc_tid_maps_operations = {
359 .open = tid_maps_open,
306 .read = seq_read, 360 .read = seq_read,
307 .llseek = seq_lseek, 361 .llseek = seq_lseek,
308 .release = seq_release_private, 362 .release = seq_release_private,
@@ -416,7 +470,7 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
416 return 0; 470 return 0;
417} 471}
418 472
419static int show_smap(struct seq_file *m, void *v) 473static int show_smap(struct seq_file *m, void *v, int is_pid)
420{ 474{
421 struct proc_maps_private *priv = m->private; 475 struct proc_maps_private *priv = m->private;
422 struct task_struct *task = priv->task; 476 struct task_struct *task = priv->task;
@@ -434,7 +488,7 @@ static int show_smap(struct seq_file *m, void *v)
434 if (vma->vm_mm && !is_vm_hugetlb_page(vma)) 488 if (vma->vm_mm && !is_vm_hugetlb_page(vma))
435 walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); 489 walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk);
436 490
437 show_map_vma(m, vma); 491 show_map_vma(m, vma, is_pid);
438 492
439 seq_printf(m, 493 seq_printf(m,
440 "Size: %8lu kB\n" 494 "Size: %8lu kB\n"
@@ -473,20 +527,49 @@ static int show_smap(struct seq_file *m, void *v)
473 return 0; 527 return 0;
474} 528}
475 529
530static int show_pid_smap(struct seq_file *m, void *v)
531{
532 return show_smap(m, v, 1);
533}
534
535static int show_tid_smap(struct seq_file *m, void *v)
536{
537 return show_smap(m, v, 0);
538}
539
476static const struct seq_operations proc_pid_smaps_op = { 540static const struct seq_operations proc_pid_smaps_op = {
477 .start = m_start, 541 .start = m_start,
478 .next = m_next, 542 .next = m_next,
479 .stop = m_stop, 543 .stop = m_stop,
480 .show = show_smap 544 .show = show_pid_smap
545};
546
547static const struct seq_operations proc_tid_smaps_op = {
548 .start = m_start,
549 .next = m_next,
550 .stop = m_stop,
551 .show = show_tid_smap
481}; 552};
482 553
483static int smaps_open(struct inode *inode, struct file *file) 554static int pid_smaps_open(struct inode *inode, struct file *file)
484{ 555{
485 return do_maps_open(inode, file, &proc_pid_smaps_op); 556 return do_maps_open(inode, file, &proc_pid_smaps_op);
486} 557}
487 558
488const struct file_operations proc_smaps_operations = { 559static int tid_smaps_open(struct inode *inode, struct file *file)
489 .open = smaps_open, 560{
561 return do_maps_open(inode, file, &proc_tid_smaps_op);
562}
563
564const struct file_operations proc_pid_smaps_operations = {
565 .open = pid_smaps_open,
566 .read = seq_read,
567 .llseek = seq_lseek,
568 .release = seq_release_private,
569};
570
571const struct file_operations proc_tid_smaps_operations = {
572 .open = tid_smaps_open,
490 .read = seq_read, 573 .read = seq_read,
491 .llseek = seq_lseek, 574 .llseek = seq_lseek,
492 .release = seq_release_private, 575 .release = seq_release_private,
@@ -1039,7 +1122,7 @@ static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask,
1039/* 1122/*
1040 * Display pages allocated per node and memory policy via /proc. 1123 * Display pages allocated per node and memory policy via /proc.
1041 */ 1124 */
1042static int show_numa_map(struct seq_file *m, void *v) 1125static int show_numa_map(struct seq_file *m, void *v, int is_pid)
1043{ 1126{
1044 struct numa_maps_private *numa_priv = m->private; 1127 struct numa_maps_private *numa_priv = m->private;
1045 struct proc_maps_private *proc_priv = &numa_priv->proc_maps; 1128 struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
@@ -1076,9 +1159,19 @@ static int show_numa_map(struct seq_file *m, void *v)
1076 seq_path(m, &file->f_path, "\n\t= "); 1159 seq_path(m, &file->f_path, "\n\t= ");
1077 } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { 1160 } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
1078 seq_printf(m, " heap"); 1161 seq_printf(m, " heap");
1079 } else if (vma->vm_start <= mm->start_stack && 1162 } else {
1080 vma->vm_end >= mm->start_stack) { 1163 pid_t tid = vm_is_stack(proc_priv->task, vma, is_pid);
1081 seq_printf(m, " stack"); 1164 if (tid != 0) {
1165 /*
1166 * Thread stack in /proc/PID/task/TID/maps or
1167 * the main process stack.
1168 */
1169 if (!is_pid || (vma->vm_start <= mm->start_stack &&
1170 vma->vm_end >= mm->start_stack))
1171 seq_printf(m, " stack");
1172 else
1173 seq_printf(m, " stack:%d", tid);
1174 }
1082 } 1175 }
1083 1176
1084 if (is_vm_hugetlb_page(vma)) 1177 if (is_vm_hugetlb_page(vma))
@@ -1121,21 +1214,39 @@ out:
1121 return 0; 1214 return 0;
1122} 1215}
1123 1216
1217static int show_pid_numa_map(struct seq_file *m, void *v)
1218{
1219 return show_numa_map(m, v, 1);
1220}
1221
1222static int show_tid_numa_map(struct seq_file *m, void *v)
1223{
1224 return show_numa_map(m, v, 0);
1225}
1226
1124static const struct seq_operations proc_pid_numa_maps_op = { 1227static const struct seq_operations proc_pid_numa_maps_op = {
1125 .start = m_start, 1228 .start = m_start,
1126 .next = m_next, 1229 .next = m_next,
1127 .stop = m_stop, 1230 .stop = m_stop,
1128 .show = show_numa_map, 1231 .show = show_pid_numa_map,
1129}; 1232};
1130 1233
1131static int numa_maps_open(struct inode *inode, struct file *file) 1234static const struct seq_operations proc_tid_numa_maps_op = {
1235 .start = m_start,
1236 .next = m_next,
1237 .stop = m_stop,
1238 .show = show_tid_numa_map,
1239};
1240
1241static int numa_maps_open(struct inode *inode, struct file *file,
1242 const struct seq_operations *ops)
1132{ 1243{
1133 struct numa_maps_private *priv; 1244 struct numa_maps_private *priv;
1134 int ret = -ENOMEM; 1245 int ret = -ENOMEM;
1135 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1246 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1136 if (priv) { 1247 if (priv) {
1137 priv->proc_maps.pid = proc_pid(inode); 1248 priv->proc_maps.pid = proc_pid(inode);
1138 ret = seq_open(file, &proc_pid_numa_maps_op); 1249 ret = seq_open(file, ops);
1139 if (!ret) { 1250 if (!ret) {
1140 struct seq_file *m = file->private_data; 1251 struct seq_file *m = file->private_data;
1141 m->private = priv; 1252 m->private = priv;
@@ -1146,8 +1257,25 @@ static int numa_maps_open(struct inode *inode, struct file *file)
1146 return ret; 1257 return ret;
1147} 1258}
1148 1259
1149const struct file_operations proc_numa_maps_operations = { 1260static int pid_numa_maps_open(struct inode *inode, struct file *file)
1150 .open = numa_maps_open, 1261{
1262 return numa_maps_open(inode, file, &proc_pid_numa_maps_op);
1263}
1264
1265static int tid_numa_maps_open(struct inode *inode, struct file *file)
1266{
1267 return numa_maps_open(inode, file, &proc_tid_numa_maps_op);
1268}
1269
1270const struct file_operations proc_pid_numa_maps_operations = {
1271 .open = pid_numa_maps_open,
1272 .read = seq_read,
1273 .llseek = seq_lseek,
1274 .release = seq_release_private,
1275};
1276
1277const struct file_operations proc_tid_numa_maps_operations = {
1278 .open = tid_numa_maps_open,
1151 .read = seq_read, 1279 .read = seq_read,
1152 .llseek = seq_lseek, 1280 .llseek = seq_lseek,
1153 .release = seq_release_private, 1281 .release = seq_release_private,
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 980de547c070..74fe164d1b23 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -134,9 +134,11 @@ static void pad_len_spaces(struct seq_file *m, int len)
134/* 134/*
135 * display a single VMA to a sequenced file 135 * display a single VMA to a sequenced file
136 */ 136 */
137static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) 137static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
138 int is_pid)
138{ 139{
139 struct mm_struct *mm = vma->vm_mm; 140 struct mm_struct *mm = vma->vm_mm;
141 struct proc_maps_private *priv = m->private;
140 unsigned long ino = 0; 142 unsigned long ino = 0;
141 struct file *file; 143 struct file *file;
142 dev_t dev = 0; 144 dev_t dev = 0;
@@ -168,10 +170,19 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
168 pad_len_spaces(m, len); 170 pad_len_spaces(m, len);
169 seq_path(m, &file->f_path, ""); 171 seq_path(m, &file->f_path, "");
170 } else if (mm) { 172 } else if (mm) {
171 if (vma->vm_start <= mm->start_stack && 173 pid_t tid = vm_is_stack(priv->task, vma, is_pid);
172 vma->vm_end >= mm->start_stack) { 174
175 if (tid != 0) {
173 pad_len_spaces(m, len); 176 pad_len_spaces(m, len);
174 seq_puts(m, "[stack]"); 177 /*
178 * Thread stack in /proc/PID/task/TID/maps or
179 * the main process stack.
180 */
181 if (!is_pid || (vma->vm_start <= mm->start_stack &&
182 vma->vm_end >= mm->start_stack))
183 seq_printf(m, "[stack]");
184 else
185 seq_printf(m, "[stack:%d]", tid);
175 } 186 }
176 } 187 }
177 188
@@ -182,11 +193,22 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
182/* 193/*
183 * display mapping lines for a particular process's /proc/pid/maps 194 * display mapping lines for a particular process's /proc/pid/maps
184 */ 195 */
185static int show_map(struct seq_file *m, void *_p) 196static int show_map(struct seq_file *m, void *_p, int is_pid)
186{ 197{
187 struct rb_node *p = _p; 198 struct rb_node *p = _p;
188 199
189 return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb)); 200 return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb),
201 is_pid);
202}
203
204static int show_pid_map(struct seq_file *m, void *_p)
205{
206 return show_map(m, _p, 1);
207}
208
209static int show_tid_map(struct seq_file *m, void *_p)
210{
211 return show_map(m, _p, 0);
190} 212}
191 213
192static void *m_start(struct seq_file *m, loff_t *pos) 214static void *m_start(struct seq_file *m, loff_t *pos)
@@ -240,10 +262,18 @@ static const struct seq_operations proc_pid_maps_ops = {
240 .start = m_start, 262 .start = m_start,
241 .next = m_next, 263 .next = m_next,
242 .stop = m_stop, 264 .stop = m_stop,
243 .show = show_map 265 .show = show_pid_map
266};
267
268static const struct seq_operations proc_tid_maps_ops = {
269 .start = m_start,
270 .next = m_next,
271 .stop = m_stop,
272 .show = show_tid_map
244}; 273};
245 274
246static int maps_open(struct inode *inode, struct file *file) 275static int maps_open(struct inode *inode, struct file *file,
276 const struct seq_operations *ops)
247{ 277{
248 struct proc_maps_private *priv; 278 struct proc_maps_private *priv;
249 int ret = -ENOMEM; 279 int ret = -ENOMEM;
@@ -251,7 +281,7 @@ static int maps_open(struct inode *inode, struct file *file)
251 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 281 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
252 if (priv) { 282 if (priv) {
253 priv->pid = proc_pid(inode); 283 priv->pid = proc_pid(inode);
254 ret = seq_open(file, &proc_pid_maps_ops); 284 ret = seq_open(file, ops);
255 if (!ret) { 285 if (!ret) {
256 struct seq_file *m = file->private_data; 286 struct seq_file *m = file->private_data;
257 m->private = priv; 287 m->private = priv;
@@ -262,8 +292,25 @@ static int maps_open(struct inode *inode, struct file *file)
262 return ret; 292 return ret;
263} 293}
264 294
265const struct file_operations proc_maps_operations = { 295static int pid_maps_open(struct inode *inode, struct file *file)
266 .open = maps_open, 296{
297 return maps_open(inode, file, &proc_pid_maps_ops);
298}
299
300static int tid_maps_open(struct inode *inode, struct file *file)
301{
302 return maps_open(inode, file, &proc_tid_maps_ops);
303}
304
305const struct file_operations proc_pid_maps_operations = {
306 .open = pid_maps_open,
307 .read = seq_read,
308 .llseek = seq_lseek,
309 .release = seq_release_private,
310};
311
312const struct file_operations proc_tid_maps_operations = {
313 .open = tid_maps_open,
267 .read = seq_read, 314 .read = seq_read,
268 .llseek = seq_lseek, 315 .llseek = seq_lseek,
269 .release = seq_release_private, 316 .release = seq_release_private,
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 378bccebc26c..df17ff23d50e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1040,6 +1040,9 @@ static inline int stack_guard_page_end(struct vm_area_struct *vma,
1040 !vma_growsup(vma->vm_next, addr); 1040 !vma_growsup(vma->vm_next, addr);
1041} 1041}
1042 1042
1043extern pid_t
1044vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group);
1045
1043extern unsigned long move_page_tables(struct vm_area_struct *vma, 1046extern unsigned long move_page_tables(struct vm_area_struct *vma,
1044 unsigned long old_addr, struct vm_area_struct *new_vma, 1047 unsigned long old_addr, struct vm_area_struct *new_vma,
1045 unsigned long new_addr, unsigned long len); 1048 unsigned long new_addr, unsigned long len);
diff --git a/mm/util.c b/mm/util.c
index 136ac4f322b8..ae962b31de88 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -239,6 +239,47 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
239 next->vm_prev = vma; 239 next->vm_prev = vma;
240} 240}
241 241
242/* Check if the vma is being used as a stack by this task */
243static int vm_is_stack_for_task(struct task_struct *t,
244 struct vm_area_struct *vma)
245{
246 return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
247}
248
249/*
250 * Check if the vma is being used as a stack.
251 * If is_group is non-zero, check in the entire thread group or else
252 * just check in the current task. Returns the pid of the task that
253 * the vma is stack for.
254 */
255pid_t vm_is_stack(struct task_struct *task,
256 struct vm_area_struct *vma, int in_group)
257{
258 pid_t ret = 0;
259
260 if (vm_is_stack_for_task(task, vma))
261 return task->pid;
262
263 if (in_group) {
264 struct task_struct *t;
265 rcu_read_lock();
266 if (!pid_alive(task))
267 goto done;
268
269 t = task;
270 do {
271 if (vm_is_stack_for_task(t, vma)) {
272 ret = t->pid;
273 goto done;
274 }
275 } while_each_thread(task, t);
276done:
277 rcu_read_unlock();
278 }
279
280 return ret;
281}
282
242#if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT) 283#if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
243void arch_pick_mmap_layout(struct mm_struct *mm) 284void arch_pick_mmap_layout(struct mm_struct *mm)
244{ 285{