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

s390/mm: implement set_memory_4k()

Implement set_memory_4k() which will split any present large or huge
mapping in the given range to a 4k mapping.

Link: https://lore.kernel.org/r/20210728190254.3921642-2-hca@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>

+18 -2
+6
arch/s390/include/asm/set_memory.h
··· 10 10 #define SET_MEMORY_RW 2UL 11 11 #define SET_MEMORY_NX 4UL 12 12 #define SET_MEMORY_X 8UL 13 + #define SET_MEMORY_4K 16UL 13 14 14 15 int __set_memory(unsigned long addr, int numpages, unsigned long flags); 15 16 ··· 32 31 static inline int set_memory_x(unsigned long addr, int numpages) 33 32 { 34 33 return __set_memory(addr, numpages, SET_MEMORY_X); 34 + } 35 + 36 + static inline int set_memory_4k(unsigned long addr, int numpages) 37 + { 38 + return __set_memory(addr, numpages, SET_MEMORY_4K); 35 39 } 36 40 37 41 #endif
+12 -2
arch/s390/mm/pageattr.c
··· 85 85 { 86 86 pte_t *ptep, new; 87 87 88 + if ((flags & SET_MEMORY_4K) == SET_MEMORY_4K) 89 + return 0; 88 90 ptep = pte_offset_kernel(pmdp, addr); 89 91 do { 90 92 new = *ptep; ··· 157 155 unsigned long flags) 158 156 { 159 157 unsigned long next; 158 + int need_split; 160 159 pmd_t *pmdp; 161 160 int rc = 0; 162 161 ··· 167 164 return -EINVAL; 168 165 next = pmd_addr_end(addr, end); 169 166 if (pmd_large(*pmdp)) { 170 - if (addr & ~PMD_MASK || addr + PMD_SIZE > next) { 167 + need_split = !!(flags & SET_MEMORY_4K); 168 + need_split |= !!(addr & ~PMD_MASK); 169 + need_split |= !!(addr + PMD_SIZE > next); 170 + if (need_split) { 171 171 rc = split_pmd_page(pmdp, addr); 172 172 if (rc) 173 173 return rc; ··· 238 232 unsigned long flags) 239 233 { 240 234 unsigned long next; 235 + int need_split; 241 236 pud_t *pudp; 242 237 int rc = 0; 243 238 ··· 248 241 return -EINVAL; 249 242 next = pud_addr_end(addr, end); 250 243 if (pud_large(*pudp)) { 251 - if (addr & ~PUD_MASK || addr + PUD_SIZE > next) { 244 + need_split = !!(flags & SET_MEMORY_4K); 245 + need_split |= !!(addr & ~PUD_MASK); 246 + need_split |= !!(addr + PUD_SIZE > next); 247 + if (need_split) { 252 248 rc = split_pud_page(pudp, addr); 253 249 if (rc) 254 250 break;