diff options
-rw-r--r-- | arch/ia64/mm/hugetlbpage.c | 6 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 5 | ||||
-rw-r--r-- | arch/s390/mm/hugetlbpage.c | 5 | ||||
-rw-r--r-- | arch/sh/mm/hugetlbpage.c | 5 | ||||
-rw-r--r-- | arch/sparc64/mm/hugetlbpage.c | 5 | ||||
-rw-r--r-- | arch/x86/mm/hugetlbpage.c | 25 | ||||
-rw-r--r-- | include/linux/hugetlb.h | 5 | ||||
-rw-r--r-- | mm/hugetlb.c | 9 | ||||
-rw-r--r-- | mm/memory.c | 15 |
9 files changed, 75 insertions, 5 deletions
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index 6170f097d255..c45fc7f5a979 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c | |||
@@ -107,6 +107,12 @@ int pmd_huge(pmd_t pmd) | |||
107 | { | 107 | { |
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | |||
111 | int pud_huge(pud_t pud) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
110 | struct page * | 116 | struct page * |
111 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write) | 117 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write) |
112 | { | 118 | { |
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index c94dc71af989..63db7adce717 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c | |||
@@ -369,6 +369,11 @@ int pmd_huge(pmd_t pmd) | |||
369 | return 0; | 369 | return 0; |
370 | } | 370 | } |
371 | 371 | ||
372 | int pud_huge(pud_t pud) | ||
373 | { | ||
374 | return 0; | ||
375 | } | ||
376 | |||
372 | struct page * | 377 | struct page * |
373 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 378 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
374 | pmd_t *pmd, int write) | 379 | pmd_t *pmd, int write) |
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 9162dc84f77f..f28c43d2f61d 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c | |||
@@ -120,6 +120,11 @@ int pmd_huge(pmd_t pmd) | |||
120 | return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE); | 120 | return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE); |
121 | } | 121 | } |
122 | 122 | ||
123 | int pud_huge(pud_t pud) | ||
124 | { | ||
125 | return 0; | ||
126 | } | ||
127 | |||
123 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 128 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
124 | pmd_t *pmdp, int write) | 129 | pmd_t *pmdp, int write) |
125 | { | 130 | { |
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c index 2f9dbe0ef4ac..9304117039c4 100644 --- a/arch/sh/mm/hugetlbpage.c +++ b/arch/sh/mm/hugetlbpage.c | |||
@@ -79,6 +79,11 @@ int pmd_huge(pmd_t pmd) | |||
79 | return 0; | 79 | return 0; |
80 | } | 80 | } |
81 | 81 | ||
82 | int pud_huge(pud_t pud) | ||
83 | { | ||
84 | return 0; | ||
85 | } | ||
86 | |||
82 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 87 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
83 | pmd_t *pmd, int write) | 88 | pmd_t *pmd, int write) |
84 | { | 89 | { |
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 1307b23f6a76..f27d10369e0c 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c | |||
@@ -295,6 +295,11 @@ int pmd_huge(pmd_t pmd) | |||
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | int pud_huge(pud_t pud) | ||
299 | { | ||
300 | return 0; | ||
301 | } | ||
302 | |||
298 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 303 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
299 | pmd_t *pmd, int write) | 304 | pmd_t *pmd, int write) |
300 | { | 305 | { |
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 52476fde8996..a4789e87a315 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c | |||
@@ -189,6 +189,11 @@ int pmd_huge(pmd_t pmd) | |||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | int pud_huge(pud_t pud) | ||
193 | { | ||
194 | return 0; | ||
195 | } | ||
196 | |||
192 | struct page * | 197 | struct page * |
193 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 198 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
194 | pmd_t *pmd, int write) | 199 | pmd_t *pmd, int write) |
@@ -209,6 +214,11 @@ int pmd_huge(pmd_t pmd) | |||
209 | return !!(pmd_val(pmd) & _PAGE_PSE); | 214 | return !!(pmd_val(pmd) & _PAGE_PSE); |
210 | } | 215 | } |
211 | 216 | ||
217 | int pud_huge(pud_t pud) | ||
218 | { | ||
219 | return 0; | ||
220 | } | ||
221 | |||
212 | struct page * | 222 | struct page * |
213 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 223 | follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
214 | pmd_t *pmd, int write) | 224 | pmd_t *pmd, int write) |
@@ -217,9 +227,22 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, | |||
217 | 227 | ||
218 | page = pte_page(*(pte_t *)pmd); | 228 | page = pte_page(*(pte_t *)pmd); |
219 | if (page) | 229 | if (page) |
220 | page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT); | 230 | page += ((address & ~PMD_MASK) >> PAGE_SHIFT); |
221 | return page; | 231 | return page; |
222 | } | 232 | } |
233 | |||
234 | struct page * | ||
235 | follow_huge_pud(struct mm_struct *mm, unsigned long address, | ||
236 | pud_t *pud, int write) | ||
237 | { | ||
238 | struct page *page; | ||
239 | |||
240 | page = pte_page(*(pte_t *)pud); | ||
241 | if (page) | ||
242 | page += ((address & ~PUD_MASK) >> PAGE_SHIFT); | ||
243 | return page; | ||
244 | } | ||
245 | |||
223 | #endif | 246 | #endif |
224 | 247 | ||
225 | /* x86_64 also uses this file */ | 248 | /* x86_64 also uses this file */ |
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 58c0de32e7f0..b2c17f62cacb 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h | |||
@@ -50,7 +50,10 @@ struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, | |||
50 | int write); | 50 | int write); |
51 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, | 51 | struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, |
52 | pmd_t *pmd, int write); | 52 | pmd_t *pmd, int write); |
53 | struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address, | ||
54 | pud_t *pud, int write); | ||
53 | int pmd_huge(pmd_t pmd); | 55 | int pmd_huge(pmd_t pmd); |
56 | int pud_huge(pud_t pmd); | ||
54 | void hugetlb_change_protection(struct vm_area_struct *vma, | 57 | void hugetlb_change_protection(struct vm_area_struct *vma, |
55 | unsigned long address, unsigned long end, pgprot_t newprot); | 58 | unsigned long address, unsigned long end, pgprot_t newprot); |
56 | 59 | ||
@@ -78,8 +81,10 @@ static inline unsigned long hugetlb_total_pages(void) | |||
78 | #define hugetlb_report_meminfo(buf) 0 | 81 | #define hugetlb_report_meminfo(buf) 0 |
79 | #define hugetlb_report_node_meminfo(n, buf) 0 | 82 | #define hugetlb_report_node_meminfo(n, buf) 0 |
80 | #define follow_huge_pmd(mm, addr, pmd, write) NULL | 83 | #define follow_huge_pmd(mm, addr, pmd, write) NULL |
84 | #define follow_huge_pud(mm, addr, pud, write) NULL | ||
81 | #define prepare_hugepage_range(file, addr, len) (-EINVAL) | 85 | #define prepare_hugepage_range(file, addr, len) (-EINVAL) |
82 | #define pmd_huge(x) 0 | 86 | #define pmd_huge(x) 0 |
87 | #define pud_huge(x) 0 | ||
83 | #define is_hugepage_only_range(mm, addr, len) 0 | 88 | #define is_hugepage_only_range(mm, addr, len) 0 |
84 | #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; }) | 89 | #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; }) |
85 | #define hugetlb_fault(mm, vma, addr, write) ({ BUG(); 0; }) | 90 | #define hugetlb_fault(mm, vma, addr, write) ({ BUG(); 0; }) |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 0c74c14dd2f7..107c1ce223cb 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -1996,6 +1996,15 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1996 | return ret; | 1996 | return ret; |
1997 | } | 1997 | } |
1998 | 1998 | ||
1999 | /* Can be overriden by architectures */ | ||
2000 | __attribute__((weak)) struct page * | ||
2001 | follow_huge_pud(struct mm_struct *mm, unsigned long address, | ||
2002 | pud_t *pud, int write) | ||
2003 | { | ||
2004 | BUG(); | ||
2005 | return NULL; | ||
2006 | } | ||
2007 | |||
1999 | int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | 2008 | int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, |
2000 | struct page **pages, struct vm_area_struct **vmas, | 2009 | struct page **pages, struct vm_area_struct **vmas, |
2001 | unsigned long *position, int *length, int i, | 2010 | unsigned long *position, int *length, int i, |
diff --git a/mm/memory.c b/mm/memory.c index 02fc6b1047b0..262e3eb6601a 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -998,19 +998,24 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, | |||
998 | goto no_page_table; | 998 | goto no_page_table; |
999 | 999 | ||
1000 | pud = pud_offset(pgd, address); | 1000 | pud = pud_offset(pgd, address); |
1001 | if (pud_none(*pud) || unlikely(pud_bad(*pud))) | 1001 | if (pud_none(*pud)) |
1002 | goto no_page_table; | ||
1003 | if (pud_huge(*pud)) { | ||
1004 | BUG_ON(flags & FOLL_GET); | ||
1005 | page = follow_huge_pud(mm, address, pud, flags & FOLL_WRITE); | ||
1006 | goto out; | ||
1007 | } | ||
1008 | if (unlikely(pud_bad(*pud))) | ||
1002 | goto no_page_table; | 1009 | goto no_page_table; |
1003 | 1010 | ||
1004 | pmd = pmd_offset(pud, address); | 1011 | pmd = pmd_offset(pud, address); |
1005 | if (pmd_none(*pmd)) | 1012 | if (pmd_none(*pmd)) |
1006 | goto no_page_table; | 1013 | goto no_page_table; |
1007 | |||
1008 | if (pmd_huge(*pmd)) { | 1014 | if (pmd_huge(*pmd)) { |
1009 | BUG_ON(flags & FOLL_GET); | 1015 | BUG_ON(flags & FOLL_GET); |
1010 | page = follow_huge_pmd(mm, address, pmd, flags & FOLL_WRITE); | 1016 | page = follow_huge_pmd(mm, address, pmd, flags & FOLL_WRITE); |
1011 | goto out; | 1017 | goto out; |
1012 | } | 1018 | } |
1013 | |||
1014 | if (unlikely(pmd_bad(*pmd))) | 1019 | if (unlikely(pmd_bad(*pmd))) |
1015 | goto no_page_table; | 1020 | goto no_page_table; |
1016 | 1021 | ||
@@ -1567,6 +1572,8 @@ static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud, | |||
1567 | unsigned long next; | 1572 | unsigned long next; |
1568 | int err; | 1573 | int err; |
1569 | 1574 | ||
1575 | BUG_ON(pud_huge(*pud)); | ||
1576 | |||
1570 | pmd = pmd_alloc(mm, pud, addr); | 1577 | pmd = pmd_alloc(mm, pud, addr); |
1571 | if (!pmd) | 1578 | if (!pmd) |
1572 | return -ENOMEM; | 1579 | return -ENOMEM; |