[RFC PATCH 3/4] kho: Implement page-aware refcount restoration
Mike Rapoport
rppt at kernel.org
Tue Jul 7 01:28:28 PDT 2026
> The KHO restoration logic currently forces a refcount of 1 on every
> page of a multi-page block. While that is correct for split pages, it
> violates the expectations of the buddy allocator for high-order
> non-compound pages allocated by kernel user (like the DMA allocator),
> where tail pages are expected to have a refcount of 0.
>
> Update the restoration path to respect the preserved page type stored
> in the page->private metadata. For KHO_PAGE_CONTIG blocks, only the
> head page is given a reference count of 1. For KHO_PAGE_SPLIT blocks,
> every page is given a reference count of 1.
>
> Signed-off-by: Pranjal Shrivastava <praan at google.com>
>
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index d6e81f72fe5de..f6ca5e24c7407 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -375,11 +375,18 @@ int kho_radix_walk_tree(struct kho_radix_tree *tree,
> }
> EXPORT_SYMBOL_GPL(kho_radix_walk_tree);
>
> -/* For physically contiguous 0-order pages. */
> -static void kho_init_pages(struct page *page, unsigned long nr_pages)
> +/* For physically contiguous pages. */
> +static void kho_restore_refcounts(struct page *page, unsigned long nr_pages,
> + enum kho_page_type type)
Why did you change the function name?
It's there to ensure proper initialization of struct pages for preserved
memory and refcount is the only part of that.
> {
> - for (unsigned long i = 0; i < nr_pages; i++) {
> - set_page_count(page + i, 1);
> + /* Head page always gets refcount of 1. */
> + set_page_count(page, 1);
> + clear_page_tag_ref(page);
> +
> + for (unsigned long i = 1; i < nr_pages; i++) {
> + unsigned int count = (type == KHO_PAGE_SPLIT) ? 1 : 0;
The count is same for all iterations, why not initialize it outside the
loop?
> +
> + set_page_count(page + i, count);
> /* Clear each page's codetag to avoid accounting mismatch. */
> clear_page_tag_ref(page + i);
> }
> @@ -387,16 +394,7 @@ static void kho_init_pages(struct page *page, unsigned long nr_pages)
>
> static void kho_init_folio(struct page *page, unsigned int order)
> {
> - unsigned long nr_pages = (1 << order);
> -
> - /* Head page gets refcount of 1. */
> - set_page_count(page, 1);
> - /* Clear head page's codetag to avoid accounting mismatch. */
> - clear_page_tag_ref(page);
> -
> - /* For higher order folios, tail pages get a page count of zero. */
> - for (unsigned long i = 1; i < nr_pages; i++)
> - set_page_count(page + i, 0);
> + kho_restore_refcounts(page, 1 << order, KHO_PAGE_CONTIG);
Ah, I see you wanted to reuse the same code for folios.
In this case you could add a helper for refcount initialization and call
it from here and from kho_init_pages().
--
Sincerely yours,
Mike.
More information about the kexec
mailing list