diff options
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r-- | fs/proc/task_mmu.c | 112 |
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 | ||
337 | static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | 340 | |
338 | struct mm_walk *walk) | 341 | static 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); | 384 | static 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) { |