diff options
Diffstat (limited to 'fs/proc/array.c')
| -rw-r--r-- | fs/proc/array.c | 92 | 
1 files changed, 91 insertions, 1 deletions
| diff --git a/fs/proc/array.c b/fs/proc/array.c index 725a650bbbb8..822c2d506518 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -82,6 +82,7 @@ | |||
| 82 | #include <linux/pid_namespace.h> | 82 | #include <linux/pid_namespace.h> | 
| 83 | #include <linux/ptrace.h> | 83 | #include <linux/ptrace.h> | 
| 84 | #include <linux/tracehook.h> | 84 | #include <linux/tracehook.h> | 
| 85 | #include <linux/swapops.h> | ||
| 85 | 86 | ||
| 86 | #include <asm/pgtable.h> | 87 | #include <asm/pgtable.h> | 
| 87 | #include <asm/processor.h> | 88 | #include <asm/processor.h> | 
| @@ -321,6 +322,94 @@ static inline void task_context_switch_counts(struct seq_file *m, | |||
| 321 | p->nivcsw); | 322 | p->nivcsw); | 
| 322 | } | 323 | } | 
| 323 | 324 | ||
| 325 | #ifdef CONFIG_MMU | ||
| 326 | |||
| 327 | struct stack_stats { | ||
| 328 | struct vm_area_struct *vma; | ||
| 329 | unsigned long startpage; | ||
| 330 | unsigned long usage; | ||
| 331 | }; | ||
| 332 | |||
| 333 | static int stack_usage_pte_range(pmd_t *pmd, unsigned long addr, | ||
| 334 | unsigned long end, struct mm_walk *walk) | ||
| 335 | { | ||
| 336 | struct stack_stats *ss = walk->private; | ||
| 337 | struct vm_area_struct *vma = ss->vma; | ||
| 338 | pte_t *pte, ptent; | ||
| 339 | spinlock_t *ptl; | ||
| 340 | int ret = 0; | ||
| 341 | |||
| 342 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | ||
| 343 | for (; addr != end; pte++, addr += PAGE_SIZE) { | ||
| 344 | ptent = *pte; | ||
| 345 | |||
| 346 | #ifdef CONFIG_STACK_GROWSUP | ||
| 347 | if (pte_present(ptent) || is_swap_pte(ptent)) | ||
| 348 | ss->usage = addr - ss->startpage + PAGE_SIZE; | ||
| 349 | #else | ||
| 350 | if (pte_present(ptent) || is_swap_pte(ptent)) { | ||
| 351 | ss->usage = ss->startpage - addr + PAGE_SIZE; | ||
| 352 | pte++; | ||
| 353 | ret = 1; | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | #endif | ||
| 357 | } | ||
| 358 | pte_unmap_unlock(pte - 1, ptl); | ||
| 359 | cond_resched(); | ||
| 360 | return ret; | ||
| 361 | } | ||
| 362 | |||
| 363 | static inline unsigned long get_stack_usage_in_bytes(struct vm_area_struct *vma, | ||
| 364 | struct task_struct *task) | ||
| 365 | { | ||
| 366 | struct stack_stats ss; | ||
| 367 | struct mm_walk stack_walk = { | ||
| 368 | .pmd_entry = stack_usage_pte_range, | ||
| 369 | .mm = vma->vm_mm, | ||
| 370 | .private = &ss, | ||
| 371 | }; | ||
| 372 | |||
| 373 | if (!vma->vm_mm || is_vm_hugetlb_page(vma)) | ||
| 374 | return 0; | ||
| 375 | |||
| 376 | ss.vma = vma; | ||
| 377 | ss.startpage = task->stack_start & PAGE_MASK; | ||
| 378 | ss.usage = 0; | ||
| 379 | |||
| 380 | #ifdef CONFIG_STACK_GROWSUP | ||
| 381 | walk_page_range(KSTK_ESP(task) & PAGE_MASK, vma->vm_end, | ||
| 382 | &stack_walk); | ||
| 383 | #else | ||
| 384 | walk_page_range(vma->vm_start, (KSTK_ESP(task) & PAGE_MASK) + PAGE_SIZE, | ||
| 385 | &stack_walk); | ||
| 386 | #endif | ||
| 387 | return ss.usage; | ||
| 388 | } | ||
| 389 | |||
| 390 | static inline void task_show_stack_usage(struct seq_file *m, | ||
| 391 | struct task_struct *task) | ||
| 392 | { | ||
| 393 | struct vm_area_struct *vma; | ||
| 394 | struct mm_struct *mm = get_task_mm(task); | ||
| 395 | |||
| 396 | if (mm) { | ||
| 397 | down_read(&mm->mmap_sem); | ||
| 398 | vma = find_vma(mm, task->stack_start); | ||
| 399 | if (vma) | ||
| 400 | seq_printf(m, "Stack usage:\t%lu kB\n", | ||
| 401 | get_stack_usage_in_bytes(vma, task) >> 10); | ||
| 402 | |||
| 403 | up_read(&mm->mmap_sem); | ||
| 404 | mmput(mm); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | #else | ||
| 408 | static void task_show_stack_usage(struct seq_file *m, struct task_struct *task) | ||
| 409 | { | ||
| 410 | } | ||
| 411 | #endif /* CONFIG_MMU */ | ||
| 412 | |||
| 324 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | 413 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | 
| 325 | struct pid *pid, struct task_struct *task) | 414 | struct pid *pid, struct task_struct *task) | 
| 326 | { | 415 | { | 
| @@ -340,6 +429,7 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | |||
| 340 | task_show_regs(m, task); | 429 | task_show_regs(m, task); | 
| 341 | #endif | 430 | #endif | 
| 342 | task_context_switch_counts(m, task); | 431 | task_context_switch_counts(m, task); | 
| 432 | task_show_stack_usage(m, task); | ||
| 343 | return 0; | 433 | return 0; | 
| 344 | } | 434 | } | 
| 345 | 435 | ||
| @@ -481,7 +571,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 481 | rsslim, | 571 | rsslim, | 
| 482 | mm ? mm->start_code : 0, | 572 | mm ? mm->start_code : 0, | 
| 483 | mm ? mm->end_code : 0, | 573 | mm ? mm->end_code : 0, | 
| 484 | (permitted && mm) ? mm->start_stack : 0, | 574 | (permitted && mm) ? task->stack_start : 0, | 
| 485 | esp, | 575 | esp, | 
| 486 | eip, | 576 | eip, | 
| 487 | /* The signal information here is obsolete. | 577 | /* The signal information here is obsolete. | 
