Commit b76437579d1344b612cf1851ae610c636cec7db0

Authored by Siddhesh Poyarekar
Committed by Linus Torvalds
1 parent 9e81130b7c

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>

Showing 7 changed files with 313 additions and 63 deletions Side-by-side Diff

Documentation/filesystems/proc.txt
... ... @@ -290,7 +290,7 @@
290 290 rsslim current limit in bytes on the rss
291 291 start_code address above which program text can run
292 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 294 esp current value of ESP
295 295 eip current value of EIP
296 296 pending bitmap of pending signals
... ... @@ -325,7 +325,7 @@
325 325 a7cb1000-a7cb2000 ---p 00000000 00:00 0
326 326 a7cb2000-a7eb2000 rw-p 00000000 00:00 0
327 327 a7eb2000-a7eb3000 ---p 00000000 00:00 0
328   -a7eb3000-a7ed5000 rw-p 00000000 00:00 0
  328 +a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack:1001]
329 329 a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6
330 330 a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6
331 331 a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6
332 332  
... ... @@ -357,11 +357,39 @@
357 357  
358 358 [heap] = the heap of the program
359 359 [stack] = the stack of the main process
  360 + [stack:1001] = the stack of the thread with tid 1001
360 361 [vdso] = the "virtual dynamic shared object",
361 362 the kernel system call handler
362 363  
363 364 or if empty, the mapping is anonymous.
364 365  
  366 +The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
  367 +of the individual tasks of a process. In this file you will see a mapping marked
  368 +as [stack] if that task sees it as a stack. This is a key difference from the
  369 +content of /proc/PID/maps, where you will see all mappings that are being used
  370 +as stack by all of those tasks. Hence, for the example above, the task-level
  371 +map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
  372 +
  373 +08048000-08049000 r-xp 00000000 03:00 8312 /opt/test
  374 +08049000-0804a000 rw-p 00001000 03:00 8312 /opt/test
  375 +0804a000-0806b000 rw-p 00000000 00:00 0 [heap]
  376 +a7cb1000-a7cb2000 ---p 00000000 00:00 0
  377 +a7cb2000-a7eb2000 rw-p 00000000 00:00 0
  378 +a7eb2000-a7eb3000 ---p 00000000 00:00 0
  379 +a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack]
  380 +a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6
  381 +a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6
  382 +a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6
  383 +a800b000-a800e000 rw-p 00000000 00:00 0
  384 +a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0
  385 +a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0
  386 +a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0
  387 +a8024000-a8027000 rw-p 00000000 00:00 0
  388 +a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2
  389 +a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2
  390 +a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2
  391 +aff35000-aff4a000 rw-p 00000000 00:00 0
  392 +ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
365 393  
366 394 The /proc/PID/smaps is an extension based on maps, showing the memory
367 395 consumption for each of the process's mappings. For each of mappings there
... ... @@ -2989,9 +2989,9 @@
2989 2989 INF("cmdline", S_IRUGO, proc_pid_cmdline),
2990 2990 ONE("stat", S_IRUGO, proc_tgid_stat),
2991 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 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 2995 #endif
2996 2996 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
2997 2997 LNK("cwd", proc_cwd_link),
... ... @@ -3002,7 +3002,7 @@
3002 3002 REG("mountstats", S_IRUSR, proc_mountstats_operations),
3003 3003 #ifdef CONFIG_PROC_PAGE_MONITOR
3004 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 3006 REG("pagemap", S_IRUGO, proc_pagemap_operations),
3007 3007 #endif
3008 3008 #ifdef CONFIG_SECURITY
3009 3009  
... ... @@ -3348,9 +3348,9 @@
3348 3348 INF("cmdline", S_IRUGO, proc_pid_cmdline),
3349 3349 ONE("stat", S_IRUGO, proc_tid_stat),
3350 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 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 3354 #endif
3355 3355 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
3356 3356 LNK("cwd", proc_cwd_link),
... ... @@ -3360,7 +3360,7 @@
3360 3360 REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
3361 3361 #ifdef CONFIG_PROC_PAGE_MONITOR
3362 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 3364 REG("pagemap", S_IRUGO, proc_pagemap_operations),
3365 3365 #endif
3366 3366 #ifdef CONFIG_SECURITY
... ... @@ -53,9 +53,12 @@
53 53 struct pid *pid, struct task_struct *task);
54 54 extern loff_t mem_lseek(struct file *file, loff_t offset, int orig);
55 55  
56   -extern const struct file_operations proc_maps_operations;
57   -extern const struct file_operations proc_numa_maps_operations;
58   -extern const struct file_operations proc_smaps_operations;
  56 +extern const struct file_operations proc_pid_maps_operations;
  57 +extern const struct file_operations proc_tid_maps_operations;
  58 +extern const struct file_operations proc_pid_numa_maps_operations;
  59 +extern const struct file_operations proc_tid_numa_maps_operations;
  60 +extern const struct file_operations proc_pid_smaps_operations;
  61 +extern const struct file_operations proc_tid_smaps_operations;
59 62 extern const struct file_operations proc_clear_refs_operations;
60 63 extern const struct file_operations proc_pagemap_operations;
61 64 extern const struct file_operations proc_net_operations;
... ... @@ -209,16 +209,20 @@
209 209 return ret;
210 210 }
211 211  
212   -static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
  212 +static void
  213 +show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
213 214 {
214 215 struct mm_struct *mm = vma->vm_mm;
215 216 struct file *file = vma->vm_file;
  217 + struct proc_maps_private *priv = m->private;
  218 + struct task_struct *task = priv->task;
216 219 vm_flags_t flags = vma->vm_flags;
217 220 unsigned long ino = 0;
218 221 unsigned long long pgoff = 0;
219 222 unsigned long start, end;
220 223 dev_t dev = 0;
221 224 int len;
  225 + const char *name = NULL;
222 226  
223 227 if (file) {
224 228 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
225 229  
226 230  
227 231  
228 232  
229 233  
... ... @@ -252,36 +256,57 @@
252 256 if (file) {
253 257 pad_len_spaces(m, len);
254 258 seq_path(m, &file->f_path, "\n");
255   - } else {
256   - const char *name = arch_vma_name(vma);
257   - if (!name) {
258   - if (mm) {
259   - if (vma->vm_start <= mm->brk &&
260   - vma->vm_end >= mm->start_brk) {
261   - name = "[heap]";
262   - } else if (vma->vm_start <= mm->start_stack &&
263   - vma->vm_end >= mm->start_stack) {
264   - name = "[stack]";
265   - }
  259 + goto done;
  260 + }
  261 +
  262 + name = arch_vma_name(vma);
  263 + if (!name) {
  264 + pid_t tid;
  265 +
  266 + if (!mm) {
  267 + name = "[vdso]";
  268 + goto done;
  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 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) {
271   - pad_len_spaces(m, len);
272   - seq_puts(m, name);
273   - }
274 293 }
  294 +
  295 +done:
  296 + if (name) {
  297 + pad_len_spaces(m, len);
  298 + seq_puts(m, name);
  299 + }
275 300 seq_putc(m, '\n');
276 301 }
277 302  
278   -static int show_map(struct seq_file *m, void *v)
  303 +static int show_map(struct seq_file *m, void *v, int is_pid)
279 304 {
280 305 struct vm_area_struct *vma = v;
281 306 struct proc_maps_private *priv = m->private;
282 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 311 if (m->count < m->size) /* vma is copied successfully */
287 312 m->version = (vma != get_gate_vma(task->mm))
288 313  
289 314  
290 315  
291 316  
... ... @@ -289,25 +314,54 @@
289 314 return 0;
290 315 }
291 316  
  317 +static int show_pid_map(struct seq_file *m, void *v)
  318 +{
  319 + return show_map(m, v, 1);
  320 +}
  321 +
  322 +static int show_tid_map(struct seq_file *m, void *v)
  323 +{
  324 + return show_map(m, v, 0);
  325 +}
  326 +
292 327 static const struct seq_operations proc_pid_maps_op = {
293 328 .start = m_start,
294 329 .next = m_next,
295 330 .stop = m_stop,
296   - .show = show_map
  331 + .show = show_pid_map
297 332 };
298 333  
299   -static int maps_open(struct inode *inode, struct file *file)
  334 +static 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
  339 +};
  340 +
  341 +static int pid_maps_open(struct inode *inode, struct file *file)
300 342 {
301 343 return do_maps_open(inode, file, &proc_pid_maps_op);
302 344 }
303 345  
304   -const struct file_operations proc_maps_operations = {
305   - .open = maps_open,
  346 +static int tid_maps_open(struct inode *inode, struct file *file)
  347 +{
  348 + return do_maps_open(inode, file, &proc_tid_maps_op);
  349 +}
  350 +
  351 +const struct file_operations proc_pid_maps_operations = {
  352 + .open = pid_maps_open,
306 353 .read = seq_read,
307 354 .llseek = seq_lseek,
308 355 .release = seq_release_private,
309 356 };
310 357  
  358 +const struct file_operations proc_tid_maps_operations = {
  359 + .open = tid_maps_open,
  360 + .read = seq_read,
  361 + .llseek = seq_lseek,
  362 + .release = seq_release_private,
  363 +};
  364 +
311 365 /*
312 366 * Proportional Set Size(PSS): my share of RSS.
313 367 *
... ... @@ -416,7 +470,7 @@
416 470 return 0;
417 471 }
418 472  
419   -static int show_smap(struct seq_file *m, void *v)
  473 +static int show_smap(struct seq_file *m, void *v, int is_pid)
420 474 {
421 475 struct proc_maps_private *priv = m->private;
422 476 struct task_struct *task = priv->task;
... ... @@ -434,7 +488,7 @@
434 488 if (vma->vm_mm && !is_vm_hugetlb_page(vma))
435 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 493 seq_printf(m,
440 494 "Size: %8lu kB\n"
441 495  
442 496  
443 497  
444 498  
... ... @@ -473,25 +527,54 @@
473 527 return 0;
474 528 }
475 529  
  530 +static int show_pid_smap(struct seq_file *m, void *v)
  531 +{
  532 + return show_smap(m, v, 1);
  533 +}
  534 +
  535 +static int show_tid_smap(struct seq_file *m, void *v)
  536 +{
  537 + return show_smap(m, v, 0);
  538 +}
  539 +
476 540 static const struct seq_operations proc_pid_smaps_op = {
477 541 .start = m_start,
478 542 .next = m_next,
479 543 .stop = m_stop,
480   - .show = show_smap
  544 + .show = show_pid_smap
481 545 };
482 546  
483   -static int smaps_open(struct inode *inode, struct file *file)
  547 +static 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
  552 +};
  553 +
  554 +static int pid_smaps_open(struct inode *inode, struct file *file)
484 555 {
485 556 return do_maps_open(inode, file, &proc_pid_smaps_op);
486 557 }
487 558  
488   -const struct file_operations proc_smaps_operations = {
489   - .open = smaps_open,
  559 +static int tid_smaps_open(struct inode *inode, struct file *file)
  560 +{
  561 + return do_maps_open(inode, file, &proc_tid_smaps_op);
  562 +}
  563 +
  564 +const struct file_operations proc_pid_smaps_operations = {
  565 + .open = pid_smaps_open,
490 566 .read = seq_read,
491 567 .llseek = seq_lseek,
492 568 .release = seq_release_private,
493 569 };
494 570  
  571 +const struct file_operations proc_tid_smaps_operations = {
  572 + .open = tid_smaps_open,
  573 + .read = seq_read,
  574 + .llseek = seq_lseek,
  575 + .release = seq_release_private,
  576 +};
  577 +
495 578 static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
496 579 unsigned long end, struct mm_walk *walk)
497 580 {
... ... @@ -1039,7 +1122,7 @@
1039 1122 /*
1040 1123 * Display pages allocated per node and memory policy via /proc.
1041 1124 */
1042   -static int show_numa_map(struct seq_file *m, void *v)
  1125 +static int show_numa_map(struct seq_file *m, void *v, int is_pid)
1043 1126 {
1044 1127 struct numa_maps_private *numa_priv = m->private;
1045 1128 struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
... ... @@ -1076,9 +1159,19 @@
1076 1159 seq_path(m, &file->f_path, "\n\t= ");
1077 1160 } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
1078 1161 seq_printf(m, " heap");
1079   - } else if (vma->vm_start <= mm->start_stack &&
1080   - vma->vm_end >= mm->start_stack) {
1081   - seq_printf(m, " stack");
  1162 + } else {
  1163 + pid_t tid = vm_is_stack(proc_priv->task, vma, is_pid);
  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 1177 if (is_vm_hugetlb_page(vma))
1085 1178  
1086 1179  
1087 1180  
... ... @@ -1121,21 +1214,39 @@
1121 1214 return 0;
1122 1215 }
1123 1216  
  1217 +static int show_pid_numa_map(struct seq_file *m, void *v)
  1218 +{
  1219 + return show_numa_map(m, v, 1);
  1220 +}
  1221 +
  1222 +static int show_tid_numa_map(struct seq_file *m, void *v)
  1223 +{
  1224 + return show_numa_map(m, v, 0);
  1225 +}
  1226 +
1124 1227 static const struct seq_operations proc_pid_numa_maps_op = {
1125   - .start = m_start,
1126   - .next = m_next,
1127   - .stop = m_stop,
1128   - .show = show_numa_map,
  1228 + .start = m_start,
  1229 + .next = m_next,
  1230 + .stop = m_stop,
  1231 + .show = show_pid_numa_map,
1129 1232 };
1130 1233  
1131   -static int numa_maps_open(struct inode *inode, struct file *file)
  1234 +static 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 +
  1241 +static int numa_maps_open(struct inode *inode, struct file *file,
  1242 + const struct seq_operations *ops)
1132 1243 {
1133 1244 struct numa_maps_private *priv;
1134 1245 int ret = -ENOMEM;
1135 1246 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1136 1247 if (priv) {
1137 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 1250 if (!ret) {
1140 1251 struct seq_file *m = file->private_data;
1141 1252 m->private = priv;
... ... @@ -1146,8 +1257,25 @@
1146 1257 return ret;
1147 1258 }
1148 1259  
1149   -const struct file_operations proc_numa_maps_operations = {
1150   - .open = numa_maps_open,
  1260 +static int pid_numa_maps_open(struct inode *inode, struct file *file)
  1261 +{
  1262 + return numa_maps_open(inode, file, &proc_pid_numa_maps_op);
  1263 +}
  1264 +
  1265 +static 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 +
  1270 +const 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 +
  1277 +const struct file_operations proc_tid_numa_maps_operations = {
  1278 + .open = tid_numa_maps_open,
1151 1279 .read = seq_read,
1152 1280 .llseek = seq_lseek,
1153 1281 .release = seq_release_private,
fs/proc/task_nommu.c
... ... @@ -134,9 +134,11 @@
134 134 /*
135 135 * display a single VMA to a sequenced file
136 136 */
137   -static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
  137 +static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
  138 + int is_pid)
138 139 {
139 140 struct mm_struct *mm = vma->vm_mm;
  141 + struct proc_maps_private *priv = m->private;
140 142 unsigned long ino = 0;
141 143 struct file *file;
142 144 dev_t dev = 0;
143 145  
... ... @@ -168,10 +170,19 @@
168 170 pad_len_spaces(m, len);
169 171 seq_path(m, &file->f_path, "");
170 172 } else if (mm) {
171   - if (vma->vm_start <= mm->start_stack &&
172   - vma->vm_end >= mm->start_stack) {
  173 + pid_t tid = vm_is_stack(priv->task, vma, is_pid);
  174 +
  175 + if (tid != 0) {
173 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  
178 189  
179 190  
... ... @@ -182,13 +193,24 @@
182 193 /*
183 194 * display mapping lines for a particular process's /proc/pid/maps
184 195 */
185   -static int show_map(struct seq_file *m, void *_p)
  196 +static int show_map(struct seq_file *m, void *_p, int is_pid)
186 197 {
187 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);
190 202 }
191 203  
  204 +static int show_pid_map(struct seq_file *m, void *_p)
  205 +{
  206 + return show_map(m, _p, 1);
  207 +}
  208 +
  209 +static int show_tid_map(struct seq_file *m, void *_p)
  210 +{
  211 + return show_map(m, _p, 0);
  212 +}
  213 +
192 214 static void *m_start(struct seq_file *m, loff_t *pos)
193 215 {
194 216 struct proc_maps_private *priv = m->private;
195 217  
... ... @@ -240,10 +262,18 @@
240 262 .start = m_start,
241 263 .next = m_next,
242 264 .stop = m_stop,
243   - .show = show_map
  265 + .show = show_pid_map
244 266 };
245 267  
246   -static int maps_open(struct inode *inode, struct file *file)
  268 +static 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
  273 +};
  274 +
  275 +static int maps_open(struct inode *inode, struct file *file,
  276 + const struct seq_operations *ops)
247 277 {
248 278 struct proc_maps_private *priv;
249 279 int ret = -ENOMEM;
... ... @@ -251,7 +281,7 @@
251 281 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
252 282 if (priv) {
253 283 priv->pid = proc_pid(inode);
254   - ret = seq_open(file, &proc_pid_maps_ops);
  284 + ret = seq_open(file, ops);
255 285 if (!ret) {
256 286 struct seq_file *m = file->private_data;
257 287 m->private = priv;
... ... @@ -262,8 +292,25 @@
262 292 return ret;
263 293 }
264 294  
265   -const struct file_operations proc_maps_operations = {
266   - .open = maps_open,
  295 +static int pid_maps_open(struct inode *inode, struct file *file)
  296 +{
  297 + return maps_open(inode, file, &proc_pid_maps_ops);
  298 +}
  299 +
  300 +static int tid_maps_open(struct inode *inode, struct file *file)
  301 +{
  302 + return maps_open(inode, file, &proc_tid_maps_ops);
  303 +}
  304 +
  305 +const 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 +
  312 +const struct file_operations proc_tid_maps_operations = {
  313 + .open = tid_maps_open,
267 314 .read = seq_read,
268 315 .llseek = seq_lseek,
269 316 .release = seq_release_private,
... ... @@ -1040,6 +1040,9 @@
1040 1040 !vma_growsup(vma->vm_next, addr);
1041 1041 }
1042 1042  
  1043 +extern pid_t
  1044 +vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group);
  1045 +
1043 1046 extern unsigned long move_page_tables(struct vm_area_struct *vma,
1044 1047 unsigned long old_addr, struct vm_area_struct *new_vma,
1045 1048 unsigned long new_addr, unsigned long len);
... ... @@ -239,6 +239,47 @@
239 239 next->vm_prev = vma;
240 240 }
241 241  
  242 +/* Check if the vma is being used as a stack by this task */
  243 +static 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 + */
  255 +pid_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);
  276 +done:
  277 + rcu_read_unlock();
  278 + }
  279 +
  280 + return ret;
  281 +}
  282 +
242 283 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
243 284 void arch_pick_mmap_layout(struct mm_struct *mm)
244 285 {