aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAdam Litke <agl@us.ibm.com>2008-11-12 16:24:56 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-11-12 20:17:16 -0500
commit7526674de0c921e7f1e9b6f71a1f9d832557b554 (patch)
tree9b40d13ecd775197b74fcb396d6aba7ce5ea589e /mm
parentb5f1f5557fd83fe92bdf2d2e80e431d655464d6c (diff)
hugetlb: make unmap_ref_private multi-size-aware
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>
Diffstat (limited to 'mm')
-rw-r--r--mm/hugetlb.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index d143ab67be4..6058b53dcb8 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1796,6 +1796,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
1796static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma, 1796static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
1797 struct page *page, unsigned long address) 1797 struct page *page, unsigned long address)
1798{ 1798{
1799 struct hstate *h = hstate_vma(vma);
1799 struct vm_area_struct *iter_vma; 1800 struct vm_area_struct *iter_vma;
1800 struct address_space *mapping; 1801 struct address_space *mapping;
1801 struct prio_tree_iter iter; 1802 struct prio_tree_iter iter;
@@ -1805,7 +1806,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
1805 * vm_pgoff is in PAGE_SIZE units, hence the different calculation 1806 * vm_pgoff is in PAGE_SIZE units, hence the different calculation
1806 * from page cache lookup which is in HPAGE_SIZE units. 1807 * from page cache lookup which is in HPAGE_SIZE units.
1807 */ 1808 */
1808 address = address & huge_page_mask(hstate_vma(vma)); 1809 address = address & huge_page_mask(h);
1809 pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) 1810 pgoff = ((address - vma->vm_start) >> PAGE_SHIFT)
1810 + (vma->vm_pgoff >> PAGE_SHIFT); 1811 + (vma->vm_pgoff >> PAGE_SHIFT);
1811 mapping = (struct address_space *)page_private(page); 1812 mapping = (struct address_space *)page_private(page);
@@ -1824,7 +1825,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
1824 */ 1825 */
1825 if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER)) 1826 if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER))
1826 unmap_hugepage_range(iter_vma, 1827 unmap_hugepage_range(iter_vma,
1827 address, address + HPAGE_SIZE, 1828 address, address + huge_page_size(h),
1828 page); 1829 page);
1829 } 1830 }
1830 1831