diff options
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r-- | fs/proc/task_mmu.c | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7faaf2acc570..4540b8f76f16 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -125,7 +125,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
125 | if (!priv->task) | 125 | if (!priv->task) |
126 | return ERR_PTR(-ESRCH); | 126 | return ERR_PTR(-ESRCH); |
127 | 127 | ||
128 | mm = mm_for_maps(priv->task); | 128 | mm = mm_access(priv->task, PTRACE_MODE_READ); |
129 | if (!mm || IS_ERR(mm)) | 129 | if (!mm || IS_ERR(mm)) |
130 | return mm; | 130 | return mm; |
131 | down_read(&mm->mmap_sem); | 131 | down_read(&mm->mmap_sem); |
@@ -393,6 +393,7 @@ struct mem_size_stats { | |||
393 | unsigned long anonymous; | 393 | unsigned long anonymous; |
394 | unsigned long anonymous_thp; | 394 | unsigned long anonymous_thp; |
395 | unsigned long swap; | 395 | unsigned long swap; |
396 | unsigned long nonlinear; | ||
396 | u64 pss; | 397 | u64 pss; |
397 | }; | 398 | }; |
398 | 399 | ||
@@ -402,24 +403,33 @@ static void smaps_pte_entry(pte_t ptent, unsigned long addr, | |||
402 | { | 403 | { |
403 | struct mem_size_stats *mss = walk->private; | 404 | struct mem_size_stats *mss = walk->private; |
404 | struct vm_area_struct *vma = mss->vma; | 405 | struct vm_area_struct *vma = mss->vma; |
405 | struct page *page; | 406 | pgoff_t pgoff = linear_page_index(vma, addr); |
407 | struct page *page = NULL; | ||
406 | int mapcount; | 408 | int mapcount; |
407 | 409 | ||
408 | if (is_swap_pte(ptent)) { | 410 | if (pte_present(ptent)) { |
409 | mss->swap += ptent_size; | 411 | page = vm_normal_page(vma, addr, ptent); |
410 | return; | 412 | } else if (is_swap_pte(ptent)) { |
413 | swp_entry_t swpent = pte_to_swp_entry(ptent); | ||
414 | |||
415 | if (!non_swap_entry(swpent)) | ||
416 | mss->swap += ptent_size; | ||
417 | else if (is_migration_entry(swpent)) | ||
418 | page = migration_entry_to_page(swpent); | ||
419 | } else if (pte_file(ptent)) { | ||
420 | if (pte_to_pgoff(ptent) != pgoff) | ||
421 | mss->nonlinear += ptent_size; | ||
411 | } | 422 | } |
412 | 423 | ||
413 | if (!pte_present(ptent)) | ||
414 | return; | ||
415 | |||
416 | page = vm_normal_page(vma, addr, ptent); | ||
417 | if (!page) | 424 | if (!page) |
418 | return; | 425 | return; |
419 | 426 | ||
420 | if (PageAnon(page)) | 427 | if (PageAnon(page)) |
421 | mss->anonymous += ptent_size; | 428 | mss->anonymous += ptent_size; |
422 | 429 | ||
430 | if (page->index != pgoff) | ||
431 | mss->nonlinear += ptent_size; | ||
432 | |||
423 | mss->resident += ptent_size; | 433 | mss->resident += ptent_size; |
424 | /* Accumulate the size in pages that have been accessed. */ | 434 | /* Accumulate the size in pages that have been accessed. */ |
425 | if (pte_young(ptent) || PageReferenced(page)) | 435 | if (pte_young(ptent) || PageReferenced(page)) |
@@ -521,6 +531,10 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) | |||
521 | (vma->vm_flags & VM_LOCKED) ? | 531 | (vma->vm_flags & VM_LOCKED) ? |
522 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); | 532 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); |
523 | 533 | ||
534 | if (vma->vm_flags & VM_NONLINEAR) | ||
535 | seq_printf(m, "Nonlinear: %8lu kB\n", | ||
536 | mss.nonlinear >> 10); | ||
537 | |||
524 | if (m->count < m->size) /* vma is copied successfully */ | 538 | if (m->count < m->size) /* vma is copied successfully */ |
525 | m->version = (vma != get_gate_vma(task->mm)) | 539 | m->version = (vma != get_gate_vma(task->mm)) |
526 | ? vma->vm_start : 0; | 540 | ? vma->vm_start : 0; |
@@ -700,6 +714,7 @@ struct pagemapread { | |||
700 | 714 | ||
701 | #define PM_PRESENT PM_STATUS(4LL) | 715 | #define PM_PRESENT PM_STATUS(4LL) |
702 | #define PM_SWAP PM_STATUS(2LL) | 716 | #define PM_SWAP PM_STATUS(2LL) |
717 | #define PM_FILE PM_STATUS(1LL) | ||
703 | #define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) | 718 | #define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) |
704 | #define PM_END_OF_BUFFER 1 | 719 | #define PM_END_OF_BUFFER 1 |
705 | 720 | ||
@@ -733,22 +748,33 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, | |||
733 | return err; | 748 | return err; |
734 | } | 749 | } |
735 | 750 | ||
736 | static u64 swap_pte_to_pagemap_entry(pte_t pte) | 751 | static void pte_to_pagemap_entry(pagemap_entry_t *pme, |
752 | struct vm_area_struct *vma, unsigned long addr, pte_t pte) | ||
737 | { | 753 | { |
738 | swp_entry_t e = pte_to_swp_entry(pte); | 754 | u64 frame, flags; |
739 | return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); | 755 | struct page *page = NULL; |
740 | } | 756 | |
741 | 757 | if (pte_present(pte)) { | |
742 | static void pte_to_pagemap_entry(pagemap_entry_t *pme, pte_t pte) | 758 | frame = pte_pfn(pte); |
743 | { | 759 | flags = PM_PRESENT; |
744 | if (is_swap_pte(pte)) | 760 | page = vm_normal_page(vma, addr, pte); |
745 | *pme = make_pme(PM_PFRAME(swap_pte_to_pagemap_entry(pte)) | 761 | } else if (is_swap_pte(pte)) { |
746 | | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP); | 762 | swp_entry_t entry = pte_to_swp_entry(pte); |
747 | else if (pte_present(pte)) | 763 | |
748 | *pme = make_pme(PM_PFRAME(pte_pfn(pte)) | 764 | frame = swp_type(entry) | |
749 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | 765 | (swp_offset(entry) << MAX_SWAPFILES_SHIFT); |
750 | else | 766 | flags = PM_SWAP; |
767 | if (is_migration_entry(entry)) | ||
768 | page = migration_entry_to_page(entry); | ||
769 | } else { | ||
751 | *pme = make_pme(PM_NOT_PRESENT); | 770 | *pme = make_pme(PM_NOT_PRESENT); |
771 | return; | ||
772 | } | ||
773 | |||
774 | if (page && !PageAnon(page)) | ||
775 | flags |= PM_FILE; | ||
776 | |||
777 | *pme = make_pme(PM_PFRAME(frame) | PM_PSHIFT(PAGE_SHIFT) | flags); | ||
752 | } | 778 | } |
753 | 779 | ||
754 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 780 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
@@ -815,7 +841,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
815 | if (vma && (vma->vm_start <= addr) && | 841 | if (vma && (vma->vm_start <= addr) && |
816 | !is_vm_hugetlb_page(vma)) { | 842 | !is_vm_hugetlb_page(vma)) { |
817 | pte = pte_offset_map(pmd, addr); | 843 | pte = pte_offset_map(pmd, addr); |
818 | pte_to_pagemap_entry(&pme, *pte); | 844 | pte_to_pagemap_entry(&pme, vma, addr, *pte); |
819 | /* unmap before userspace copy */ | 845 | /* unmap before userspace copy */ |
820 | pte_unmap(pte); | 846 | pte_unmap(pte); |
821 | } | 847 | } |
@@ -869,11 +895,11 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, | |||
869 | * For each page in the address space, this file contains one 64-bit entry | 895 | * For each page in the address space, this file contains one 64-bit entry |
870 | * consisting of the following: | 896 | * consisting of the following: |
871 | * | 897 | * |
872 | * Bits 0-55 page frame number (PFN) if present | 898 | * Bits 0-54 page frame number (PFN) if present |
873 | * Bits 0-4 swap type if swapped | 899 | * Bits 0-4 swap type if swapped |
874 | * Bits 5-55 swap offset if swapped | 900 | * Bits 5-54 swap offset if swapped |
875 | * Bits 55-60 page shift (page size = 1<<page shift) | 901 | * Bits 55-60 page shift (page size = 1<<page shift) |
876 | * Bit 61 reserved for future use | 902 | * Bit 61 page is file-page or shared-anon |
877 | * Bit 62 page swapped | 903 | * Bit 62 page swapped |
878 | * Bit 63 page present | 904 | * Bit 63 page present |
879 | * | 905 | * |
@@ -919,7 +945,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
919 | if (!pm.buffer) | 945 | if (!pm.buffer) |
920 | goto out_task; | 946 | goto out_task; |
921 | 947 | ||
922 | mm = mm_for_maps(task); | 948 | mm = mm_access(task, PTRACE_MODE_READ); |
923 | ret = PTR_ERR(mm); | 949 | ret = PTR_ERR(mm); |
924 | if (!mm || IS_ERR(mm)) | 950 | if (!mm || IS_ERR(mm)) |
925 | goto out_free; | 951 | goto out_free; |