aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/task_mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r--fs/proc/task_mmu.c112
1 files changed, 74 insertions, 38 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index e73314afc53..7c708a418ac 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1,5 +1,6 @@
1#include <linux/mm.h> 1#include <linux/mm.h>
2#include <linux/hugetlb.h> 2#include <linux/hugetlb.h>
3#include <linux/huge_mm.h>
3#include <linux/mount.h> 4#include <linux/mount.h>
4#include <linux/seq_file.h> 5#include <linux/seq_file.h>
5#include <linux/highmem.h> 6#include <linux/highmem.h>
@@ -7,6 +8,7 @@
7#include <linux/slab.h> 8#include <linux/slab.h>
8#include <linux/pagemap.h> 9#include <linux/pagemap.h>
9#include <linux/mempolicy.h> 10#include <linux/mempolicy.h>
11#include <linux/rmap.h>
10#include <linux/swap.h> 12#include <linux/swap.h>
11#include <linux/swapops.h> 13#include <linux/swapops.h>
12 14
@@ -249,8 +251,8 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
249 const char *name = arch_vma_name(vma); 251 const char *name = arch_vma_name(vma);
250 if (!name) { 252 if (!name) {
251 if (mm) { 253 if (mm) {
252 if (vma->vm_start <= mm->start_brk && 254 if (vma->vm_start <= mm->brk &&
253 vma->vm_end >= mm->brk) { 255 vma->vm_end >= mm->start_brk) {
254 name = "[heap]"; 256 name = "[heap]";
255 } else if (vma->vm_start <= mm->start_stack && 257 } else if (vma->vm_start <= mm->start_stack &&
256 vma->vm_end >= mm->start_stack) { 258 vma->vm_end >= mm->start_stack) {
@@ -330,58 +332,86 @@ struct mem_size_stats {
330 unsigned long private_dirty; 332 unsigned long private_dirty;
331 unsigned long referenced; 333 unsigned long referenced;
332 unsigned long anonymous; 334 unsigned long anonymous;
335 unsigned long anonymous_thp;
333 unsigned long swap; 336 unsigned long swap;
334 u64 pss; 337 u64 pss;
335}; 338};
336 339
337static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, 340
338 struct mm_walk *walk) 341static void smaps_pte_entry(pte_t ptent, unsigned long addr,
342 unsigned long ptent_size, struct mm_walk *walk)
339{ 343{
340 struct mem_size_stats *mss = walk->private; 344 struct mem_size_stats *mss = walk->private;
341 struct vm_area_struct *vma = mss->vma; 345 struct vm_area_struct *vma = mss->vma;
342 pte_t *pte, ptent;
343 spinlock_t *ptl;
344 struct page *page; 346 struct page *page;
345 int mapcount; 347 int mapcount;
346 348
347 pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); 349 if (is_swap_pte(ptent)) {
348 for (; addr != end; pte++, addr += PAGE_SIZE) { 350 mss->swap += ptent_size;
349 ptent = *pte; 351 return;
350 352 }
351 if (is_swap_pte(ptent)) {
352 mss->swap += PAGE_SIZE;
353 continue;
354 }
355 353
356 if (!pte_present(ptent)) 354 if (!pte_present(ptent))
357 continue; 355 return;
356
357 page = vm_normal_page(vma, addr, ptent);
358 if (!page)
359 return;
360
361 if (PageAnon(page))
362 mss->anonymous += ptent_size;
363
364 mss->resident += ptent_size;
365 /* Accumulate the size in pages that have been accessed. */
366 if (pte_young(ptent) || PageReferenced(page))
367 mss->referenced += ptent_size;
368 mapcount = page_mapcount(page);
369 if (mapcount >= 2) {
370 if (pte_dirty(ptent) || PageDirty(page))
371 mss->shared_dirty += ptent_size;
372 else
373 mss->shared_clean += ptent_size;
374 mss->pss += (ptent_size << PSS_SHIFT) / mapcount;
375 } else {
376 if (pte_dirty(ptent) || PageDirty(page))
377 mss->private_dirty += ptent_size;
378 else
379 mss->private_clean += ptent_size;
380 mss->pss += (ptent_size << PSS_SHIFT);
381 }
382}
358 383
359 page = vm_normal_page(vma, addr, ptent); 384static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
360 if (!page) 385 struct mm_walk *walk)
361 continue; 386{
387 struct mem_size_stats *mss = walk->private;
388 struct vm_area_struct *vma = mss->vma;
389 pte_t *pte;
390 spinlock_t *ptl;
362 391
363 if (PageAnon(page)) 392 spin_lock(&walk->mm->page_table_lock);
364 mss->anonymous += PAGE_SIZE; 393 if (pmd_trans_huge(*pmd)) {
365 394 if (pmd_trans_splitting(*pmd)) {
366 mss->resident += PAGE_SIZE; 395 spin_unlock(&walk->mm->page_table_lock);
367 /* Accumulate the size in pages that have been accessed. */ 396 wait_split_huge_page(vma->anon_vma, pmd);
368 if (pte_young(ptent) || PageReferenced(page))
369 mss->referenced += PAGE_SIZE;
370 mapcount = page_mapcount(page);
371 if (mapcount >= 2) {
372 if (pte_dirty(ptent) || PageDirty(page))
373 mss->shared_dirty += PAGE_SIZE;
374 else
375 mss->shared_clean += PAGE_SIZE;
376 mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
377 } else { 397 } else {
378 if (pte_dirty(ptent) || PageDirty(page)) 398 smaps_pte_entry(*(pte_t *)pmd, addr,
379 mss->private_dirty += PAGE_SIZE; 399 HPAGE_PMD_SIZE, walk);
380 else 400 spin_unlock(&walk->mm->page_table_lock);
381 mss->private_clean += PAGE_SIZE; 401 mss->anonymous_thp += HPAGE_PMD_SIZE;
382 mss->pss += (PAGE_SIZE << PSS_SHIFT); 402 return 0;
383 } 403 }
404 } else {
405 spin_unlock(&walk->mm->page_table_lock);
384 } 406 }
407 /*
408 * The mmap_sem held all the way back in m_start() is what
409 * keeps khugepaged out of here and from collapsing things
410 * in here.
411 */
412 pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
413 for (; addr != end; pte++, addr += PAGE_SIZE)
414 smaps_pte_entry(*pte, addr, PAGE_SIZE, walk);
385 pte_unmap_unlock(pte - 1, ptl); 415 pte_unmap_unlock(pte - 1, ptl);
386 cond_resched(); 416 cond_resched();
387 return 0; 417 return 0;
@@ -417,6 +447,7 @@ static int show_smap(struct seq_file *m, void *v)
417 "Private_Dirty: %8lu kB\n" 447 "Private_Dirty: %8lu kB\n"
418 "Referenced: %8lu kB\n" 448 "Referenced: %8lu kB\n"
419 "Anonymous: %8lu kB\n" 449 "Anonymous: %8lu kB\n"
450 "AnonHugePages: %8lu kB\n"
420 "Swap: %8lu kB\n" 451 "Swap: %8lu kB\n"
421 "KernelPageSize: %8lu kB\n" 452 "KernelPageSize: %8lu kB\n"
422 "MMUPageSize: %8lu kB\n" 453 "MMUPageSize: %8lu kB\n"
@@ -430,6 +461,7 @@ static int show_smap(struct seq_file *m, void *v)
430 mss.private_dirty >> 10, 461 mss.private_dirty >> 10,
431 mss.referenced >> 10, 462 mss.referenced >> 10,
432 mss.anonymous >> 10, 463 mss.anonymous >> 10,
464 mss.anonymous_thp >> 10,
433 mss.swap >> 10, 465 mss.swap >> 10,
434 vma_kernel_pagesize(vma) >> 10, 466 vma_kernel_pagesize(vma) >> 10,
435 vma_mmu_pagesize(vma) >> 10, 467 vma_mmu_pagesize(vma) >> 10,
@@ -469,6 +501,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
469 spinlock_t *ptl; 501 spinlock_t *ptl;
470 struct page *page; 502 struct page *page;
471 503
504 split_huge_page_pmd(walk->mm, pmd);
505
472 pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); 506 pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
473 for (; addr != end; pte++, addr += PAGE_SIZE) { 507 for (; addr != end; pte++, addr += PAGE_SIZE) {
474 ptent = *pte; 508 ptent = *pte;
@@ -625,6 +659,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
625 pte_t *pte; 659 pte_t *pte;
626 int err = 0; 660 int err = 0;
627 661
662 split_huge_page_pmd(walk->mm, pmd);
663
628 /* find the first VMA at or above 'addr' */ 664 /* find the first VMA at or above 'addr' */
629 vma = find_vma(walk->mm, addr); 665 vma = find_vma(walk->mm, addr);
630 for (; addr != end; addr += PAGE_SIZE) { 666 for (; addr != end; addr += PAGE_SIZE) {