diff options
author | Adam Litke <agl@us.ibm.com> | 2008-11-12 13:24:56 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-11-20 14:54:46 -0800 |
commit | 6fc576fc6c06dc972f5bb0a78bb76e81e9860d2b (patch) | |
tree | 1ec67e75c4e9abe34e270e54f820a09d19295f5c /mm/hugetlb.c | |
parent | 5f33ce31fb5cffd4daf1bd4aedd0936983524b0a (diff) |
hugetlb: make unmap_ref_private multi-size-aware
commit 7526674de0c921e7f1e9b6f71a1f9d832557b554 upstream.
Oops. Part of the hugetlb private reservation code was not fully
converted to use hstates.
When a huge page must be unmapped from VMAs due to a failed COW,
HPAGE_SIZE is used in the call to unmap_hugepage_range() regardless of
the page size being used. This works if the VMA is using the default
huge page size. Otherwise we might unmap too much, too little, or
trigger a BUG_ON. Rare but serious -- fix it.
Signed-off-by: Adam Litke <agl@us.ibm.com>
Cc: Jon Tollefson <kniht@linux.vnet.ibm.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r-- | mm/hugetlb.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 77427c8443a..81e9a82bfe3 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1797,6 +1797,7 @@ int unmap_ref_private(struct mm_struct *mm, struct page *page, unsigned long address) { + struct hstate *h = hstate_vma(vma); struct vm_area_struct *iter_vma; struct address_space *mapping; struct prio_tree_iter iter; @@ -1806,7 +1807,7 @@ int unmap_ref_private(struct mm_struct *mm, * vm_pgoff is in PAGE_SIZE units, hence the different calculation * from page cache lookup which is in HPAGE_SIZE units. */ - address = address & huge_page_mask(hstate_vma(vma)); + address = address & huge_page_mask(h); pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + (vma->vm_pgoff >> PAGE_SHIFT); mapping = (struct address_space *)page_private(page); @@ -1825,7 +1826,7 @@ int unmap_ref_private(struct mm_struct *mm, */ if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER)) unmap_hugepage_range(iter_vma, - address, address + HPAGE_SIZE, + address, address + huge_page_size(h), page); } |