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

s390/vmem: Support 2G page splitting for KASAN shadow freeing

Export split_pud_page() so it can be used from the vmem code and teach
modify_pud_table() to split PUD-sized mappings when only a subrange
needs to be removed.

If the range to be removed covers a full PUD-sized mapping, keep the
existing behavior: clear the PUD entry and free the backing large page
(for non-direct mappings). Otherwise, split the PUD-mapped page into
PMD mappings and let the walker handle the smaller ranges.

This is needed for KASAN early shadow removal support: memory hotplug
freeing the KASAN early shadow is the only expected caller that will
try to free 2G PUD-mapped regions of non-direct mappings.

Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>

authored by

Vasily Gorbik and committed by
Heiko Carstens
6a35d02f 1442bb87

+8 -2
+2
arch/s390/include/asm/page.h
··· 166 166 return CC_TRANSFORM(cc); 167 167 } 168 168 169 + int split_pud_page(pud_t *pudp, unsigned long addr); 170 + 169 171 /* Bits int the storage key */ 170 172 #define _PAGE_CHANGED 0x02 /* HW changed bit */ 171 173 #define _PAGE_REFERENCED 0x04 /* HW referenced bit */
+1 -1
arch/s390/mm/pageattr.c
··· 204 204 return rc; 205 205 } 206 206 207 - static int split_pud_page(pud_t *pudp, unsigned long addr) 207 + int split_pud_page(pud_t *pudp, unsigned long addr) 208 208 { 209 209 unsigned long pmd_addr, prot; 210 210 pmd_t *pm_dir, *pmdp;
+5 -1
arch/s390/mm/vmem.c
··· 330 330 if (pud_leaf(*pud)) { 331 331 if (IS_ALIGNED(addr, PUD_SIZE) && 332 332 IS_ALIGNED(next, PUD_SIZE)) { 333 + if (!direct) 334 + vmem_free_pages(pud_deref(*pud), get_order(PUD_SIZE), altmap); 333 335 pud_clear(pud); 334 336 pages++; 337 + continue; 338 + } else { 339 + split_pud_page(pud, addr & PUD_MASK); 335 340 } 336 - continue; 337 341 } 338 342 } else if (pud_none(*pud)) { 339 343 if (IS_ALIGNED(addr, PUD_SIZE) &&