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

mm/hugetlb: add more arch-defined huge_pte functions

Commit abf09bed3cce ("s390/mm: implement software dirty bits")
introduced another difference in the pte layout vs. the pmd layout on
s390, thoroughly breaking the s390 support for hugetlbfs. This requires
replacing some more pte_xxx functions in mm/hugetlbfs.c with a
huge_pte_xxx version.

This patch introduces those huge_pte_xxx functions and their generic
implementation in asm-generic/hugetlb.h, which will now be included on
all architectures supporting hugetlbfs apart from s390. This change
will be a no-op for those architectures.

[akpm@linux-foundation.org: fix warning]
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Cc: Hillf Danton <dhillf@gmail.com>
Acked-by: Michal Hocko <mhocko@suse.cz> [for !s390 parts]
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Gerald Schaefer and committed by
Linus Torvalds
106c992a 146732ce

+156 -68
+1
arch/ia64/include/asm/hugetlb.h
··· 2 2 #define _ASM_IA64_HUGETLB_H 3 3 4 4 #include <asm/page.h> 5 + #include <asm-generic/hugetlb.h> 5 6 6 7 7 8 void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr,
+1
arch/mips/include/asm/hugetlb.h
··· 10 10 #define __ASM_HUGETLB_H 11 11 12 12 #include <asm/page.h> 13 + #include <asm-generic/hugetlb.h> 13 14 14 15 15 16 static inline int is_hugepage_only_range(struct mm_struct *mm,
+1
arch/powerpc/include/asm/hugetlb.h
··· 3 3 4 4 #ifdef CONFIG_HUGETLB_PAGE 5 5 #include <asm/page.h> 6 + #include <asm-generic/hugetlb.h> 6 7 7 8 extern struct kmem_cache *hugepte_cache; 8 9
+55 -1
arch/s390/include/asm/hugetlb.h
··· 114 114 #define huge_ptep_set_wrprotect(__mm, __addr, __ptep) \ 115 115 ({ \ 116 116 pte_t __pte = huge_ptep_get(__ptep); \ 117 - if (pte_write(__pte)) { \ 117 + if (huge_pte_write(__pte)) { \ 118 118 huge_ptep_invalidate(__mm, __addr, __ptep); \ 119 119 set_huge_pte_at(__mm, __addr, __ptep, \ 120 120 huge_pte_wrprotect(__pte)); \ ··· 125 125 unsigned long address, pte_t *ptep) 126 126 { 127 127 huge_ptep_invalidate(vma->vm_mm, address, ptep); 128 + } 129 + 130 + static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot) 131 + { 132 + pte_t pte; 133 + pmd_t pmd; 134 + 135 + pmd = mk_pmd_phys(page_to_phys(page), pgprot); 136 + pte_val(pte) = pmd_val(pmd); 137 + return pte; 138 + } 139 + 140 + static inline int huge_pte_write(pte_t pte) 141 + { 142 + pmd_t pmd; 143 + 144 + pmd_val(pmd) = pte_val(pte); 145 + return pmd_write(pmd); 146 + } 147 + 148 + static inline int huge_pte_dirty(pte_t pte) 149 + { 150 + /* No dirty bit in the segment table entry. */ 151 + return 0; 152 + } 153 + 154 + static inline pte_t huge_pte_mkwrite(pte_t pte) 155 + { 156 + pmd_t pmd; 157 + 158 + pmd_val(pmd) = pte_val(pte); 159 + pte_val(pte) = pmd_val(pmd_mkwrite(pmd)); 160 + return pte; 161 + } 162 + 163 + static inline pte_t huge_pte_mkdirty(pte_t pte) 164 + { 165 + /* No dirty bit in the segment table entry. */ 166 + return pte; 167 + } 168 + 169 + static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot) 170 + { 171 + pmd_t pmd; 172 + 173 + pmd_val(pmd) = pte_val(pte); 174 + pte_val(pte) = pmd_val(pmd_modify(pmd, newprot)); 175 + return pte; 176 + } 177 + 178 + static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, 179 + pte_t *ptep) 180 + { 181 + pmd_clear((pmd_t *) ptep); 128 182 } 129 183 130 184 #endif /* _ASM_S390_HUGETLB_H */
+40 -55
arch/s390/include/asm/pgtable.h
··· 424 424 #define __S110 PAGE_RW 425 425 #define __S111 PAGE_RW 426 426 427 + /* 428 + * Segment entry (large page) protection definitions. 429 + */ 430 + #define SEGMENT_NONE __pgprot(_HPAGE_TYPE_NONE) 431 + #define SEGMENT_RO __pgprot(_HPAGE_TYPE_RO) 432 + #define SEGMENT_RW __pgprot(_HPAGE_TYPE_RW) 433 + 427 434 static inline int mm_exclusive(struct mm_struct *mm) 428 435 { 429 436 return likely(mm == current->active_mm && ··· 921 914 #ifdef CONFIG_HUGETLB_PAGE 922 915 static inline pte_t pte_mkhuge(pte_t pte) 923 916 { 924 - /* 925 - * PROT_NONE needs to be remapped from the pte type to the ste type. 926 - * The HW invalid bit is also different for pte and ste. The pte 927 - * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE 928 - * bit, so we don't have to clear it. 929 - */ 930 - if (pte_val(pte) & _PAGE_INVALID) { 931 - if (pte_val(pte) & _PAGE_SWT) 932 - pte_val(pte) |= _HPAGE_TYPE_NONE; 933 - pte_val(pte) |= _SEGMENT_ENTRY_INV; 934 - } 935 - /* 936 - * Clear SW pte bits, there are no SW bits in a segment table entry. 937 - */ 938 - pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX | _PAGE_SWC | 939 - _PAGE_SWR | _PAGE_SWW); 940 - /* 941 - * Also set the change-override bit because we don't need dirty bit 942 - * tracking for hugetlbfs pages. 943 - */ 944 917 pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO); 945 918 return pte; 946 919 } ··· 1265 1278 } 1266 1279 } 1267 1280 1268 - #ifdef CONFIG_TRANSPARENT_HUGEPAGE 1269 - 1270 - #define SEGMENT_NONE __pgprot(_HPAGE_TYPE_NONE) 1271 - #define SEGMENT_RO __pgprot(_HPAGE_TYPE_RO) 1272 - #define SEGMENT_RW __pgprot(_HPAGE_TYPE_RW) 1273 - 1274 - #define __HAVE_ARCH_PGTABLE_DEPOSIT 1275 - extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable); 1276 - 1277 - #define __HAVE_ARCH_PGTABLE_WITHDRAW 1278 - extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm); 1279 - 1280 - static inline int pmd_trans_splitting(pmd_t pmd) 1281 - { 1282 - return pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT; 1283 - } 1284 - 1285 - static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, 1286 - pmd_t *pmdp, pmd_t entry) 1287 - { 1288 - if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1) 1289 - pmd_val(entry) |= _SEGMENT_ENTRY_CO; 1290 - *pmdp = entry; 1291 - } 1292 - 1281 + #if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE) 1293 1282 static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot) 1294 1283 { 1295 1284 /* ··· 1286 1323 return pmd; 1287 1324 } 1288 1325 1289 - static inline pmd_t pmd_mkhuge(pmd_t pmd) 1326 + static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot) 1290 1327 { 1291 - pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE; 1292 - return pmd; 1328 + pmd_t __pmd; 1329 + pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot); 1330 + return __pmd; 1293 1331 } 1294 1332 1295 1333 static inline pmd_t pmd_mkwrite(pmd_t pmd) ··· 1298 1334 /* Do not clobber _HPAGE_TYPE_NONE pages! */ 1299 1335 if (!(pmd_val(pmd) & _SEGMENT_ENTRY_INV)) 1300 1336 pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO; 1337 + return pmd; 1338 + } 1339 + #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */ 1340 + 1341 + #ifdef CONFIG_TRANSPARENT_HUGEPAGE 1342 + 1343 + #define __HAVE_ARCH_PGTABLE_DEPOSIT 1344 + extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable); 1345 + 1346 + #define __HAVE_ARCH_PGTABLE_WITHDRAW 1347 + extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm); 1348 + 1349 + static inline int pmd_trans_splitting(pmd_t pmd) 1350 + { 1351 + return pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT; 1352 + } 1353 + 1354 + static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, 1355 + pmd_t *pmdp, pmd_t entry) 1356 + { 1357 + if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1) 1358 + pmd_val(entry) |= _SEGMENT_ENTRY_CO; 1359 + *pmdp = entry; 1360 + } 1361 + 1362 + static inline pmd_t pmd_mkhuge(pmd_t pmd) 1363 + { 1364 + pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE; 1301 1365 return pmd; 1302 1366 } 1303 1367 ··· 1422 1430 __pmd_idte(address, pmdp); 1423 1431 set_pmd_at(mm, address, pmdp, pmd_wrprotect(pmd)); 1424 1432 } 1425 - } 1426 - 1427 - static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot) 1428 - { 1429 - pmd_t __pmd; 1430 - pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot); 1431 - return __pmd; 1432 1433 } 1433 1434 1434 1435 #define pfn_pmd(pfn, pgprot) mk_pmd_phys(__pa((pfn) << PAGE_SHIFT), (pgprot))
+1 -1
arch/s390/mm/hugetlbpage.c
··· 39 39 if (!ptep) 40 40 return -ENOMEM; 41 41 42 - pte = mk_pte(page, PAGE_RW); 42 + pte_val(pte) = addr; 43 43 for (i = 0; i < PTRS_PER_PTE; i++) { 44 44 set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte); 45 45 pte_val(pte) += PAGE_SIZE;
+1
arch/sh/include/asm/hugetlb.h
··· 3 3 4 4 #include <asm/cacheflush.h> 5 5 #include <asm/page.h> 6 + #include <asm-generic/hugetlb.h> 6 7 7 8 8 9 static inline int is_hugepage_only_range(struct mm_struct *mm,
+1
arch/sparc/include/asm/hugetlb.h
··· 2 2 #define _ASM_SPARC64_HUGETLB_H 3 3 4 4 #include <asm/page.h> 5 + #include <asm-generic/hugetlb.h> 5 6 6 7 7 8 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+1
arch/tile/include/asm/hugetlb.h
··· 16 16 #define _ASM_TILE_HUGETLB_H 17 17 18 18 #include <asm/page.h> 19 + #include <asm-generic/hugetlb.h> 19 20 20 21 21 22 static inline int is_hugepage_only_range(struct mm_struct *mm,
+1
arch/x86/include/asm/hugetlb.h
··· 2 2 #define _ASM_X86_HUGETLB_H 3 3 4 4 #include <asm/page.h> 5 + #include <asm-generic/hugetlb.h> 5 6 6 7 7 8 static inline int is_hugepage_only_range(struct mm_struct *mm,
+40
include/asm-generic/hugetlb.h
··· 1 + #ifndef _ASM_GENERIC_HUGETLB_H 2 + #define _ASM_GENERIC_HUGETLB_H 3 + 4 + static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot) 5 + { 6 + return mk_pte(page, pgprot); 7 + } 8 + 9 + static inline int huge_pte_write(pte_t pte) 10 + { 11 + return pte_write(pte); 12 + } 13 + 14 + static inline int huge_pte_dirty(pte_t pte) 15 + { 16 + return pte_dirty(pte); 17 + } 18 + 19 + static inline pte_t huge_pte_mkwrite(pte_t pte) 20 + { 21 + return pte_mkwrite(pte); 22 + } 23 + 24 + static inline pte_t huge_pte_mkdirty(pte_t pte) 25 + { 26 + return pte_mkdirty(pte); 27 + } 28 + 29 + static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot) 30 + { 31 + return pte_modify(pte, newprot); 32 + } 33 + 34 + static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, 35 + pte_t *ptep) 36 + { 37 + pte_clear(mm, addr, ptep); 38 + } 39 + 40 + #endif /* _ASM_GENERIC_HUGETLB_H */
+13 -11
mm/hugetlb.c
··· 2247 2247 pte_t entry; 2248 2248 2249 2249 if (writable) { 2250 - entry = 2251 - pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); 2250 + entry = huge_pte_mkwrite(huge_pte_mkdirty(mk_huge_pte(page, 2251 + vma->vm_page_prot))); 2252 2252 } else { 2253 - entry = huge_pte_wrprotect(mk_pte(page, vma->vm_page_prot)); 2253 + entry = huge_pte_wrprotect(mk_huge_pte(page, 2254 + vma->vm_page_prot)); 2254 2255 } 2255 2256 entry = pte_mkyoung(entry); 2256 2257 entry = pte_mkhuge(entry); ··· 2265 2264 { 2266 2265 pte_t entry; 2267 2266 2268 - entry = pte_mkwrite(pte_mkdirty(huge_ptep_get(ptep))); 2267 + entry = huge_pte_mkwrite(huge_pte_mkdirty(huge_ptep_get(ptep))); 2269 2268 if (huge_ptep_set_access_flags(vma, address, ptep, entry, 1)) 2270 2269 update_mmu_cache(vma, address, ptep); 2271 2270 } ··· 2380 2379 * HWPoisoned hugepage is already unmapped and dropped reference 2381 2380 */ 2382 2381 if (unlikely(is_hugetlb_entry_hwpoisoned(pte))) { 2383 - pte_clear(mm, address, ptep); 2382 + huge_pte_clear(mm, address, ptep); 2384 2383 continue; 2385 2384 } 2386 2385 ··· 2404 2403 2405 2404 pte = huge_ptep_get_and_clear(mm, address, ptep); 2406 2405 tlb_remove_tlb_entry(tlb, ptep, address); 2407 - if (pte_dirty(pte)) 2406 + if (huge_pte_dirty(pte)) 2408 2407 set_page_dirty(page); 2409 2408 2410 2409 page_remove_rmap(page); ··· 2857 2856 * page now as it is used to determine if a reservation has been 2858 2857 * consumed. 2859 2858 */ 2860 - if ((flags & FAULT_FLAG_WRITE) && !pte_write(entry)) { 2859 + if ((flags & FAULT_FLAG_WRITE) && !huge_pte_write(entry)) { 2861 2860 if (vma_needs_reservation(h, vma, address) < 0) { 2862 2861 ret = VM_FAULT_OOM; 2863 2862 goto out_mutex; ··· 2887 2886 2888 2887 2889 2888 if (flags & FAULT_FLAG_WRITE) { 2890 - if (!pte_write(entry)) { 2889 + if (!huge_pte_write(entry)) { 2891 2890 ret = hugetlb_cow(mm, vma, address, ptep, entry, 2892 2891 pagecache_page); 2893 2892 goto out_page_table_lock; 2894 2893 } 2895 - entry = pte_mkdirty(entry); 2894 + entry = huge_pte_mkdirty(entry); 2896 2895 } 2897 2896 entry = pte_mkyoung(entry); 2898 2897 if (huge_ptep_set_access_flags(vma, address, ptep, entry, ··· 2973 2972 * directly from any kind of swap entries. 2974 2973 */ 2975 2974 if (absent || is_swap_pte(huge_ptep_get(pte)) || 2976 - ((flags & FOLL_WRITE) && !pte_write(huge_ptep_get(pte)))) { 2975 + ((flags & FOLL_WRITE) && 2976 + !huge_pte_write(huge_ptep_get(pte)))) { 2977 2977 int ret; 2978 2978 2979 2979 spin_unlock(&mm->page_table_lock); ··· 3044 3042 } 3045 3043 if (!huge_pte_none(huge_ptep_get(ptep))) { 3046 3044 pte = huge_ptep_get_and_clear(mm, address, ptep); 3047 - pte = pte_mkhuge(pte_modify(pte, newprot)); 3045 + pte = pte_mkhuge(huge_pte_modify(pte, newprot)); 3048 3046 pte = arch_make_huge_pte(pte, vma, NULL, 0); 3049 3047 set_huge_pte_at(mm, address, ptep, pte); 3050 3048 pages++;