Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hugepage: fix broken check for offset alignment in hugepage mappings

For hugepage mappings, the file offset, like the address and size, needs to
be aligned to the size of a hugepage.

In commit 68589bc353037f233fe510ad9ff432338c95db66, the check for this was
moved into prepare_hugepage_range() along with the address and size checks.
But since BenH's rework of the get_unmapped_area() paths leading up to
commit 4b1d89290b62bb2db476c94c82cf7442aab440c8, prepare_hugepage_range()
is only called for MAP_FIXED mappings, not for other mappings. This means
we're no longer ever checking for an aligned offset - I've confirmed that
mmap() will (apparently) succeed with a misaligned offset on both powerpc
and i386 at least.

This patch restores the check, removing it from prepare_hugepage_range()
and putting it back into hugetlbfs_file_mmap(). I'm putting it there,
rather than in the get_unmapped_area() path so it only needs to go in one
place, than separately in the half-dozen or so arch-specific
implementations of hugetlb_get_unmapped_area().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Cc: Adam Litke <agl@us.ibm.com>
Cc: Andi Kleen <ak@suse.de>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Gibson and committed by
Linus Torvalds
dec4ad86 4a58448b

+17 -18
+1 -1
arch/i386/mm/hugetlbpage.c
··· 367 367 return -ENOMEM; 368 368 369 369 if (flags & MAP_FIXED) { 370 - if (prepare_hugepage_range(addr, len, pgoff)) 370 + if (prepare_hugepage_range(addr, len)) 371 371 return -EINVAL; 372 372 return addr; 373 373 }
+2 -4
arch/ia64/mm/hugetlbpage.c
··· 75 75 * Don't actually need to do any preparation, but need to make sure 76 76 * the address is in the right region. 77 77 */ 78 - int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff) 78 + int prepare_hugepage_range(unsigned long addr, unsigned long len) 79 79 { 80 - if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) 81 - return -EINVAL; 82 80 if (len & ~HPAGE_MASK) 83 81 return -EINVAL; 84 82 if (addr & ~HPAGE_MASK) ··· 149 151 150 152 /* Handle MAP_FIXED */ 151 153 if (flags & MAP_FIXED) { 152 - if (prepare_hugepage_range(addr, len, pgoff)) 154 + if (prepare_hugepage_range(addr, len)) 153 155 return -EINVAL; 154 156 return addr; 155 157 }
+1 -1
arch/sparc64/mm/hugetlbpage.c
··· 175 175 return -ENOMEM; 176 176 177 177 if (flags & MAP_FIXED) { 178 - if (prepare_hugepage_range(addr, len, pgoff)) 178 + if (prepare_hugepage_range(addr, len)) 179 179 return -EINVAL; 180 180 return addr; 181 181 }
+10 -5
fs/hugetlbfs/inode.c
··· 82 82 int ret; 83 83 84 84 /* 85 - * vma alignment has already been checked by prepare_hugepage_range. 86 - * If you add any error returns here, do so after setting VM_HUGETLB, 87 - * so is_vm_hugetlb_page tests below unmap_region go the right way 88 - * when do_mmap_pgoff unwinds (may be important on powerpc and ia64). 85 + * vma address alignment (but not the pgoff alignment) has 86 + * already been checked by prepare_hugepage_range. If you add 87 + * any error returns here, do so after setting VM_HUGETLB, so 88 + * is_vm_hugetlb_page tests below unmap_region go the right 89 + * way when do_mmap_pgoff unwinds (may be important on powerpc 90 + * and ia64). 89 91 */ 90 92 vma->vm_flags |= VM_HUGETLB | VM_RESERVED; 91 93 vma->vm_ops = &hugetlb_vm_ops; 94 + 95 + if (vma->vm_pgoff & ~(HPAGE_MASK >> PAGE_SHIFT)) 96 + return -EINVAL; 92 97 93 98 vma_len = (loff_t)(vma->vm_end - vma->vm_start); 94 99 ··· 137 132 return -ENOMEM; 138 133 139 134 if (flags & MAP_FIXED) { 140 - if (prepare_hugepage_range(addr, len, pgoff)) 135 + if (prepare_hugepage_range(addr, len)) 141 136 return -EINVAL; 142 137 return addr; 143 138 }
+3 -7
include/linux/hugetlb.h
··· 66 66 * If the arch doesn't supply something else, assume that hugepage 67 67 * size aligned regions are ok without further preparation. 68 68 */ 69 - static inline int prepare_hugepage_range(unsigned long addr, unsigned long len, 70 - pgoff_t pgoff) 69 + static inline int prepare_hugepage_range(unsigned long addr, unsigned long len) 71 70 { 72 - if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) 73 - return -EINVAL; 74 71 if (len & ~HPAGE_MASK) 75 72 return -EINVAL; 76 73 if (addr & ~HPAGE_MASK) ··· 75 78 return 0; 76 79 } 77 80 #else 78 - int prepare_hugepage_range(unsigned long addr, unsigned long len, 79 - pgoff_t pgoff); 81 + int prepare_hugepage_range(unsigned long addr, unsigned long len); 80 82 #endif 81 83 82 84 #ifndef ARCH_HAS_SETCLEAR_HUGE_PTE ··· 113 117 #define hugetlb_report_meminfo(buf) 0 114 118 #define hugetlb_report_node_meminfo(n, buf) 0 115 119 #define follow_huge_pmd(mm, addr, pmd, write) NULL 116 - #define prepare_hugepage_range(addr,len,pgoff) (-EINVAL) 120 + #define prepare_hugepage_range(addr,len) (-EINVAL) 117 121 #define pmd_huge(x) 0 118 122 #define is_hugepage_only_range(mm, addr, len) 0 119 123 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })