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

Merge patch series "riscv: fix debug_pagealloc"

Nam Cao <namcao@linutronix.de> says:

The debug_pagealloc feature is not functional on RISCV. With this feature
enabled (CONFIG_DEBUG_PAGEALLOC=y and debug_pagealloc=on), kernel crashes
early during boot.

QEMU command that can reproduce this problem:
qemu-system-riscv64 -machine virt \
-kernel Image \
-append "console=ttyS0 root=/dev/vda debug_pagealloc=on" \
-nographic \
-drive "file=root.img,format=raw,id=hd0" \
-device virtio-blk-device,drive=hd0 \
-m 4G \

This series makes debug_pagealloc functional.

* b4-shazam-merge:
riscv: rewrite __kernel_map_pages() to fix sleeping in invalid context
riscv: force PAGE_SIZE linear mapping if debug_pagealloc is enabled

Link: https://lore.kernel.org/r/cover.1715750938.git.namcao@linutronix.de
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>

+25 -6
+3
arch/riscv/mm/init.c
··· 683 683 static uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va, 684 684 phys_addr_t size) 685 685 { 686 + if (debug_pagealloc_enabled()) 687 + return PAGE_SIZE; 688 + 686 689 if (pgtable_l5_enabled && 687 690 !(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE) 688 691 return P4D_SIZE;
+22 -6
arch/riscv/mm/pageattr.c
··· 387 387 } 388 388 389 389 #ifdef CONFIG_DEBUG_PAGEALLOC 390 + static int debug_pagealloc_set_page(pte_t *pte, unsigned long addr, void *data) 391 + { 392 + int enable = *(int *)data; 393 + 394 + unsigned long val = pte_val(ptep_get(pte)); 395 + 396 + if (enable) 397 + val |= _PAGE_PRESENT; 398 + else 399 + val &= ~_PAGE_PRESENT; 400 + 401 + set_pte(pte, __pte(val)); 402 + 403 + return 0; 404 + } 405 + 390 406 void __kernel_map_pages(struct page *page, int numpages, int enable) 391 407 { 392 408 if (!debug_pagealloc_enabled()) 393 409 return; 394 410 395 - if (enable) 396 - __set_memory((unsigned long)page_address(page), numpages, 397 - __pgprot(_PAGE_PRESENT), __pgprot(0)); 398 - else 399 - __set_memory((unsigned long)page_address(page), numpages, 400 - __pgprot(0), __pgprot(_PAGE_PRESENT)); 411 + unsigned long start = (unsigned long)page_address(page); 412 + unsigned long size = PAGE_SIZE * numpages; 413 + 414 + apply_to_existing_page_range(&init_mm, start, size, debug_pagealloc_set_page, &enable); 415 + 416 + flush_tlb_kernel_range(start, start + size); 401 417 } 402 418 #endif 403 419