From f4d55ef3b81d1187f3a2c93b91a87127e5516bd5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 8 Mar 2003 03:26:43 -0800 Subject: [PATCH] [PATCH] hugetlb unmap_vmas() SMP && PREEMPT fix Patch from Kevin Pedretti The unmap_vmas() logic is designed to chew away at all the pages without holding off preemption for too long. But with CONFIG_SMP=y and CONFIG_PREEMPT=y the number of pages which we batch up between rescheduling opportunities is not a multiple of HPAGE_SIZE. So unmap_vmas() ends up calling unmap_hugepage_range() with a poorly aligned&sized region, and it goes BUG. Fix that up by ensuring that we always work across hugepage regions in HPAGE_SIZE chunks. --- include/linux/hugetlb.h | 1 + mm/memory.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 74785731a8c5f..ce564083904d9 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -66,6 +66,7 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) #ifndef HPAGE_MASK #define HPAGE_MASK 0 /* Keep the compiler happy */ +#define HPAGE_SIZE 0 #endif #endif /* !CONFIG_HUGETLB_PAGE */ diff --git a/mm/memory.c b/mm/memory.c index 1372176d3e5e8..4dde601165305 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -484,6 +484,16 @@ void unmap_page_range(struct mmu_gather *tlb, struct vm_area_struct *vma, #define ZAP_BLOCK_SIZE (~(0UL)) #endif +/* + * hugepage regions must be unmapped with HPAGE_SIZE granularity + */ +static inline unsigned long zap_block_size(struct vm_area_struct *vma) +{ + if (is_vm_hugetlb_page(vma)) + return HPAGE_SIZE; + return ZAP_BLOCK_SIZE; +} + /** * unmap_vmas - unmap a range of memory covered by a list of vma's * @tlbp: address of the caller's struct mmu_gather @@ -514,7 +524,7 @@ int unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long start_addr, unsigned long end_addr, unsigned long *nr_accounted) { - unsigned long zap_bytes = ZAP_BLOCK_SIZE; + unsigned long zap_bytes = zap_block_size(vma); unsigned long tlb_start; /* For tlb_finish_mmu */ int tlb_start_valid = 0; int ret = 0; @@ -562,7 +572,7 @@ int unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm, *tlbp = tlb_gather_mmu(mm, 0); tlb_start_valid = 0; } - zap_bytes = ZAP_BLOCK_SIZE; + zap_bytes = zap_block_size(vma); } if (vma->vm_next && vma->vm_next->vm_start < vma->vm_end) printk("%s: VMA list is not sorted correctly!\n", -- 2.53.0