arm64: kexec: stop cloning the linear map 16 times (2.65s -> 0.57s per load) - #24
Open
Yury-MonZon wants to merge 1 commit into
Open
arm64: kexec: stop cloning the linear map 16 times (2.65s -> 0.57s per load)#24Yury-MonZon wants to merge 1 commit into
Yury-MonZon wants to merge 1 commit into
Conversation
kexec_file_load() fails on arm64 if we have CONFIG_ARM64_VA_BITS_52 but it runs on a !FEAT_LPA2 host (such as my loving Grace machine). That is because trans_pgd_create_copy() uses the compile time PAGE_OFFSET (VA 52) instead of the actual VA size (48 -- due to the lack of LPA2). With the fifth level folded, pgd_none() is always false, so the walk cannot skip the 15 extra PGDIR_SIZE slots, and they all alias back to the same table: the whole kernel page table gets cloned 16 times, KASAN shadow included. Without KASAN it does not blow up, it just wastes ~RAM/32 in page tables. Fix it by copying the linear map that is the actual one, not the compiled one. Fixes: a6bbf5d ("arm64: mm: Add definitions to support 5 levels of paging") Signed-off-by: Breno Leitao <leitao@debian.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cherry-picked from the list, not written here: arm64: trans_pgd: clone only the linear map that exists at runtime by Breno Leitao, posted to linux-arm-kernel on 2026-08-28 and not yet merged. Applied with
git am, so his authorship and sign-off are intact and it will deduplicate when it lands upstream.Why this board is affected
trans_pgd_create_copy()walks from the compile-timePAGE_OFFSET. We buildCONFIG_ARM64_VA_BITS=52and RK3576 has no FEAT_LPA2, sovabits_actualis 48: the fifth level is folded,pgd_none()is never true, and the 15 extraPGDIR_SIZEslots all alias the same table. The kernel page table gets cloned 16 times on everykexecload.Upstream reports it as wasted memory. On this board it is mostly wasted time, because every profile switch that cannot be pivoted into goes through a kexec load.
Measured on Flipper One, 8GB, kernel 7.2.0 with and without the patch
machine_kexec_post_loadtimed with ftrace (function_graph,set_graph_function=machine_kexec_post_load), page-table pages counted with thefunctiontracer onkimage_alloc_control_pages, load timed aroundkexec -lof a profile's own BLS entry (11MB compressed kernel, 10MB initrd):trans_pgd_create_copykexec -lThe 16.9x matches the 16 aliased clones exactly, which is what confirms this is the whole bug rather than one contributor to it.
Two supporting measurements, from before the fix, that show what the cost was made of:
mem=2G, loading the same image. A 10MB initrd added 58ms; reading kernel and initrd off btrfs cold was 0.08s;rodata=onchanged nothing.kimage_alloc_pageper payload page and no retries, so it was never destination-collision thrash.What this does and does not buy
A kexec boot to first pixel on this board was 13.4-16.5s, of which the load was 2.65s. With the load at 0.566s that is ~2.1s off any profile switch that has to kexec, and it makes an armed prefetch cheap in memory (87MB rather than 300MB) so keeping one loaded while the boot menu waits costs little.
It does not touch the 10.5s underneath, which is a fresh kernel plus systemd reaching the panel. Only a pivot avoids that, and pivots stay at 6.3-6.6s.
Testing
Verified on Flipper One, 8GB, with a kernel built from this branch.
Load path, measured (numbers above), and reproducible: five consecutive loads of an
overlay-free profile came in at 0.469 / 0.414 / 0.408 / 0.423 / 0.442s, and five of a profile
whose device tree is assembled from an overlay at 0.440 / 0.414 / 0.419 / 0.429 / 0.417s. The
2.65s before the patch had no such spread to speak of, being dominated by a fixed walk.
Jumps, seven of them, all successful. This is the check that mattered: the patch changes
which range is cloned into the transitional table, and a table missing a page the relocation
touches does not boot slowly, it hangs with the MMU off and no console output. Both device
tree shapes were exercised, because they place their segments differently:
Every one reached userspace in 34s wall from the request,
machine_kexec.obuildswarning-free with the device config, and hibernate is untouched since it keeps calling
trans_pgd_create_copy.
Worth sending these numbers to the upstream thread: the author reports the memory waste and
has no timing from a non-LPA2 board.