I am looking for a way to split the kernel's huge page (2MiB) mappings into the smaller (4KiB) page table entries. So far, I only encountered the function set_memory_4k, which only works during the early boot stage (global variable early_boot_irqs_disabled must be true). I am a bit reluctant to disable interrupts to call this function, but I don't know of any other way to split a kernel (not user) page table.
The goal is to map individual 4KB pages with different permissions. However, pages returned via alloc_pages() are often part of 2MB mappings. I do not have an option to use any other allocator (vmalloc, kmalloc, memblock, ...), so I am required to use the alloc_pages() function or any of its variants.
Additional information:
I am aware of the existing function split_huge_page. Unfortunately this approach is not working for struct pages representing kernel memory. The reason for this (according to LWN) is that the page->mapping field, which is checked before the split, needs to be non-NULL. This doesn't apply to kernel pages, so this approach also only seems to work for user space pages.