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

s390/thp: respect page protection in pmd_none() and pmd_present()

Similar to pte_none() and pte_present(), the pmd functions should also
respect page protection of huge pages, especially PROT_NONE.
This patch also simplifies massage_pgprot_pmd() by adding new definitions
for huge page protection.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Gerald Schaefer and committed by
Martin Schwidefsky
d8e7a33d 156152f8

+22 -13
+22 -13
arch/s390/include/asm/pgtable.h
··· 506 506 507 507 static inline int pmd_present(pmd_t pmd) 508 508 { 509 - return (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) != 0UL; 509 + unsigned long mask = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO; 510 + return (pmd_val(pmd) & mask) == _HPAGE_TYPE_NONE || 511 + !(pmd_val(pmd) & _SEGMENT_ENTRY_INV); 510 512 } 511 513 512 514 static inline int pmd_none(pmd_t pmd) 513 515 { 514 - return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) != 0UL; 516 + return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) && 517 + !(pmd_val(pmd) & _SEGMENT_ENTRY_RO); 515 518 } 516 519 517 520 static inline int pmd_large(pmd_t pmd) ··· 1226 1223 } 1227 1224 1228 1225 #ifdef CONFIG_TRANSPARENT_HUGEPAGE 1226 + 1227 + #define SEGMENT_NONE __pgprot(_HPAGE_TYPE_NONE) 1228 + #define SEGMENT_RO __pgprot(_HPAGE_TYPE_RO) 1229 + #define SEGMENT_RW __pgprot(_HPAGE_TYPE_RW) 1230 + 1229 1231 #define __HAVE_ARCH_PGTABLE_DEPOSIT 1230 1232 extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable); 1231 1233 ··· 1250 1242 1251 1243 static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot) 1252 1244 { 1253 - unsigned long pgprot_pmd = 0; 1254 - 1255 - if (pgprot_val(pgprot) & _PAGE_INVALID) { 1256 - if (pgprot_val(pgprot) & _PAGE_SWT) 1257 - pgprot_pmd |= _HPAGE_TYPE_NONE; 1258 - pgprot_pmd |= _SEGMENT_ENTRY_INV; 1259 - } 1260 - if (pgprot_val(pgprot) & _PAGE_RO) 1261 - pgprot_pmd |= _SEGMENT_ENTRY_RO; 1262 - return pgprot_pmd; 1245 + /* 1246 + * pgprot is PAGE_NONE, PAGE_RO, or PAGE_RW (see __Pxxx / __Sxxx) 1247 + * Convert to segment table entry format. 1248 + */ 1249 + if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE)) 1250 + return pgprot_val(SEGMENT_NONE); 1251 + if (pgprot_val(pgprot) == pgprot_val(PAGE_RO)) 1252 + return pgprot_val(SEGMENT_RO); 1253 + return pgprot_val(SEGMENT_RW); 1263 1254 } 1264 1255 1265 1256 static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) ··· 1276 1269 1277 1270 static inline pmd_t pmd_mkwrite(pmd_t pmd) 1278 1271 { 1279 - pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO; 1272 + /* Do not clobber _HPAGE_TYPE_NONE pages! */ 1273 + if (!(pmd_val(pmd) & _SEGMENT_ENTRY_INV)) 1274 + pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO; 1280 1275 return pmd; 1281 1276 } 1282 1277