summaryrefslogtreecommitdiff
path: root/fs/proc/task_mmu.c
diff options
context:
space:
mode:
authorNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>2010-04-06 14:35:04 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-04-07 08:38:04 -0700
commit116354d177ba2da37e91cf884e3d11e67f825efd (patch)
tree150227e8a5c9ce8b6dd9333593ed513c8c012686 /fs/proc/task_mmu.c
parent57119c34e53bbb8d244c3ff1335ef5145768538f (diff)
downloadlinux-3.10-116354d177ba2da37e91cf884e3d11e67f825efd.tar.gz
linux-3.10-116354d177ba2da37e91cf884e3d11e67f825efd.tar.bz2
linux-3.10-116354d177ba2da37e91cf884e3d11e67f825efd.zip
pagemap: fix pfn calculation for hugepage
When we look into pagemap using page-types with option -p, the value of pfn for hugepages looks wrong (see below.) This is because pte was evaluated only once for one vma although it should be updated for each hugepage. This patch fixes it. $ page-types -p 3277 -Nl -b huge voffset offset len flags 7f21e8a00 11e400 1 ___U___________H_G________________ 7f21e8a01 11e401 1ff ________________TG________________ ^^^ 7f21e8c00 11e400 1 ___U___________H_G________________ 7f21e8c01 11e401 1ff ________________TG________________ ^^^ One hugepage contains 1 head page and 511 tail pages in x86_64 and each two lines represent each hugepage. Voffset and offset mean virtual address and physical address in the page unit, respectively. The different hugepages should not have the same offset value. With this patch applied: $ page-types -p 3386 -Nl -b huge voffset offset len flags 7fec7a600 112c00 1 ___UD__________H_G________________ 7fec7a601 112c01 1ff ________________TG________________ ^^^ 7fec7a800 113200 1 ___UD__________H_G________________ 7fec7a801 113201 1ff ________________TG________________ ^^^ OK More info: - This patch modifies walk_page_range()'s hugepage walker. But the change only affects pagemap_read(), which is the only caller of hugepage callback. - Without this patch, hugetlb_entry() callback is called per vma, that doesn't match the natural expectation from its name. - With this patch, hugetlb_entry() is called per hugepte entry and the callback can become much simpler. Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Acked-by: Matt Mackall <mpm@selenic.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r--fs/proc/task_mmu.c27
1 files changed, 7 insertions, 20 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index a05a669510a..070553427dd 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -662,31 +662,18 @@ static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset)
return pme;
}
-static int pagemap_hugetlb_range(pte_t *pte, unsigned long addr,
- unsigned long end, struct mm_walk *walk)
+/* This function walks within one hugetlb entry in the single call */
+static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask,
+ unsigned long addr, unsigned long end,
+ struct mm_walk *walk)
{
- struct vm_area_struct *vma;
struct pagemapread *pm = walk->private;
- struct hstate *hs = NULL;
int err = 0;
+ u64 pfn;
- vma = find_vma(walk->mm, addr);
- if (vma)
- hs = hstate_vma(vma);
for (; addr != end; addr += PAGE_SIZE) {
- u64 pfn = PM_NOT_PRESENT;
-
- if (vma && (addr >= vma->vm_end)) {
- vma = find_vma(walk->mm, addr);
- if (vma)
- hs = hstate_vma(vma);
- }
-
- if (vma && (vma->vm_start <= addr) && is_vm_hugetlb_page(vma)) {
- /* calculate pfn of the "raw" page in the hugepage. */
- int offset = (addr & ~huge_page_mask(hs)) >> PAGE_SHIFT;
- pfn = huge_pte_to_pagemap_entry(*pte, offset);
- }
+ int offset = (addr & ~hmask) >> PAGE_SHIFT;
+ pfn = huge_pte_to_pagemap_entry(*pte, offset);
err = add_to_pagemap(addr, pfn, pm);
if (err)
return err;