Commit 16fbdce6 authored by Konstantin Khlebnikov's avatar Konstantin Khlebnikov Committed by Linus Torvalds

proc/pid/pagemap: correctly report non-present ptes and holes between vmas

Reset the current pagemap-entry if the current pte isn't present, or if
current vma is over.  Otherwise pagemap reports last entry again and
again.

Non-present pte reporting was broken in commit 092b50ba ("pagemap:
introduce data structure for pagemap entry")

Reporting for holes was broken in commit 5aaabe83 ("pagemap: avoid
splitting thp when reading /proc/pid/pagemap")
Signed-off-by: default avatarKonstantin Khlebnikov <khlebnikov@openvz.org>
Reported-by: default avatarPavel Emelyanov <xemul@parallels.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Andi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent bc46f937
...@@ -747,6 +747,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, pte_t pte) ...@@ -747,6 +747,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, pte_t pte)
else if (pte_present(pte)) else if (pte_present(pte))
*pme = make_pme(PM_PFRAME(pte_pfn(pte)) *pme = make_pme(PM_PFRAME(pte_pfn(pte))
| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
else
*pme = make_pme(PM_NOT_PRESENT);
} }
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE
...@@ -761,6 +763,8 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, ...@@ -761,6 +763,8 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
if (pmd_present(pmd)) if (pmd_present(pmd))
*pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset)
| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
else
*pme = make_pme(PM_NOT_PRESENT);
} }
#else #else
static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
...@@ -801,8 +805,10 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, ...@@ -801,8 +805,10 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
/* check to see if we've left 'vma' behind /* check to see if we've left 'vma' behind
* and need a new, higher one */ * and need a new, higher one */
if (vma && (addr >= vma->vm_end)) if (vma && (addr >= vma->vm_end)) {
vma = find_vma(walk->mm, addr); vma = find_vma(walk->mm, addr);
pme = make_pme(PM_NOT_PRESENT);
}
/* check that 'vma' actually covers this address, /* check that 'vma' actually covers this address,
* and that it isn't a huge page vma */ * and that it isn't a huge page vma */
...@@ -830,6 +836,8 @@ static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, ...@@ -830,6 +836,8 @@ static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme,
if (pte_present(pte)) if (pte_present(pte))
*pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset)
| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
else
*pme = make_pme(PM_NOT_PRESENT);
} }
/* This function walks within one hugetlb entry in the single call */ /* This function walks within one hugetlb entry in the single call */
...@@ -839,7 +847,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, ...@@ -839,7 +847,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask,
{ {
struct pagemapread *pm = walk->private; struct pagemapread *pm = walk->private;
int err = 0; int err = 0;
pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); pagemap_entry_t pme;
for (; addr != end; addr += PAGE_SIZE) { for (; addr != end; addr += PAGE_SIZE) {
int offset = (addr & ~hmask) >> PAGE_SHIFT; int offset = (addr & ~hmask) >> PAGE_SHIFT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment