* [PATCH v4 0/2] kho: support preserving high-order non-compound pages
@ 2026-08-03 11:39 Pranjal Shrivastava
2026-08-03 11:39 ` [PATCH v4 1/2] kho: Introduce a helper to init high order pages Pranjal Shrivastava
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Pranjal Shrivastava @ 2026-08-03 11:39 UTC (permalink / raw)
To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav
Cc: Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm,
linux-kernel, Pranjal Shrivastava
Introduction
============
This series is required for the ongoing effort to preserve DMA allocations
across KHO [1]. It addresses a fundamental mismatch between the current KHO
restoration logic and the physical reality of high-order buddy allocations.
The Problem
===========
The current KHO restore implementation treats all multi-page blocks as
split pages during restoration. Specifically, kho_restore_pages()
initializes every 4KB sub-page with a refcount of 1.
However, many kernel subsystems, most notably the DMA allocator (via
dma_alloc_coherent), frequently return high-order non-compound pages.
In this state, only the head page carries a refcount of 1, while
all tail pages have a refcount of 0.
Consequently, when these contiguous blocks are restored by KHO in
the new kernel, the forced reference count of 1 on tail pages causes some
trouble with the buddy allocator. Downstream of the eventual free path,
__free_pages_prepare() [2] ends up calling page_expected_state() [3]
when is_check_pages_enabled() returns true (triggered when CONFIG_DEBUG_VM
is enabled or debug_pagealloc=on).
This detects the unexpected non-zero reference counts on tail pages [4] and
incorrectly taints the kernel while leaking the physical pages in question.
Proposed Solution
=================
Following feedback on the v1 RFC, this series moves away from auto type
detection and instead introduces explicit preserve / restore APIs for
high-order pages.
Callers now explicitly preserve these high-order blocks as a single unit by using
kho_preserve_page() and kho_restore_page(). These functions apply a refcount
of 1 to the head page while leaving tail pages at 0.
The existing APIs (kho_preserve_pages / kho_restore_pages) remain as is
for ranges of independent 4KB pages, continuing to use the split refcount.
The internal initialization logic is refactored to provide a helper:
kho_init_high_order_page(), which is shared between folios and high-order page
restore APIs. We also consolidate the common metadata validation, state
clearing, and managed page accounting into __kho_restore_page() to avoid duplication.
[v4]
- Consolidated adjust_managed_page_count() within __kho_restore_page()
[v3]
- Renamed "unsplit" terminology to "high-order".
- Consolidated the common restoration code (magic checks, private
clearing etc.) into the internal __kho_restore_page() helper.
[v2]
- https://lore.kernel.org/all/20260713204935.3069000-1-praan@google.com/
- Dropped automatic type detection via higher bits in Radix key.
- Introduced explicit kho_preserve_page and kho_restore_page helpers.
- Refactored internal init logic to share code between folios & high-order pages.
[v1] https://lore.kernel.org/all/20260703020832.1731864-1-praan@google.com/
Thanks,
Praan
[1] https://lore.kernel.org/all/20260708234854.4044652-1-skhawaja@google.com/
[2] https://elixir.bootlin.com/linux/v7.1.1/source/mm/page_alloc.c#L1370
[3] https://elixir.bootlin.com/linux/v7.1.1/source/mm/page_alloc.c#L1027
[4] https://elixir.bootlin.com/linux/v7.1.1/source/mm/page_alloc.c#L1034
Pranjal Shrivastava (2):
kho: Introduce a helper to init high order pages
kho: Introduce preserve/restore APIs for high-order pages
include/linux/kexec_handover.h | 10 +++
kernel/liveupdate/kexec_handover.c | 127 ++++++++++++++++++++++++-----
2 files changed, 115 insertions(+), 22 deletions(-)
base-commit: 8ba098e6b6ff0db8edf28528d1552be261af30d4
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v4 1/2] kho: Introduce a helper to init high order pages 2026-08-03 11:39 [PATCH v4 0/2] kho: support preserving high-order non-compound pages Pranjal Shrivastava @ 2026-08-03 11:39 ` Pranjal Shrivastava 2026-08-12 10:54 ` Pratyush Yadav 2026-08-03 11:39 ` [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages Pranjal Shrivastava 2026-08-11 10:27 ` [PATCH v4 0/2] kho: support preserving high-order non-compound pages Mike Rapoport 2 siblings, 1 reply; 12+ messages in thread From: Pranjal Shrivastava @ 2026-08-03 11:39 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel, Pranjal Shrivastava The current KHO restoration logic assumes all multi-page blocks are split into independent 4KB pages. Break out a helper to prepare for supporting high-order non-compound pages. Extract kho_init_high_order_page() to handle the refcount pattern where only the head page is refcounted. Use the helper for folio restoration that requires a similar refcount logic. Reviewed-by: Samiullah Khawaja <skhawaja@google.com> Signed-off-by: Pranjal Shrivastava <praan@google.com> --- kernel/liveupdate/kexec_handover.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 4834a809985a..e836efd98795 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -357,6 +357,24 @@ int kho_radix_walk_tree(struct kho_radix_tree *tree, } EXPORT_SYMBOL_GPL(kho_radix_walk_tree); +/* For physically contiguous pages. */ +static void kho_init_high_order_page(struct page *page, unsigned int order) +{ + unsigned long nr_pages = (1UL << 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 high-order blocks, tail pages get a page count of zero. */ + for (unsigned long i = 1; i < nr_pages; i++) { + set_page_count(page + i, 0); + /* Clear each page's codetag to avoid accounting mismatch. */ + clear_page_tag_ref(page + i); + } +} + /* For physically contiguous 0-order pages. */ static void kho_init_pages(struct page *page, unsigned long nr_pages) { @@ -369,16 +387,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_init_high_order_page(page, order); if (order > 0) prep_compound_page(page, order); -- 2.55.0.508.g3f0d502094-goog ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 1/2] kho: Introduce a helper to init high order pages 2026-08-03 11:39 ` [PATCH v4 1/2] kho: Introduce a helper to init high order pages Pranjal Shrivastava @ 2026-08-12 10:54 ` Pratyush Yadav 2026-08-12 12:33 ` Pranjal Shrivastava 0 siblings, 1 reply; 12+ messages in thread From: Pratyush Yadav @ 2026-08-12 10:54 UTC (permalink / raw) To: Pranjal Shrivastava Cc: Mike Rapoport, Pasha Tatashin, Pratyush Yadav, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Mon, Aug 03 2026, Pranjal Shrivastava wrote: > The current KHO restoration logic assumes all multi-page blocks are > split into independent 4KB pages. Break out a helper to prepare for > supporting high-order non-compound pages. > > Extract kho_init_high_order_page() to handle the refcount pattern > where only the head page is refcounted. Use the helper for folio > restoration that requires a similar refcount logic. > > Reviewed-by: Samiullah Khawaja <skhawaja@google.com> > Signed-off-by: Pranjal Shrivastava <praan@google.com> > --- > kernel/liveupdate/kexec_handover.c | 29 +++++++++++++++++++---------- > 1 file changed, 19 insertions(+), 10 deletions(-) > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > index 4834a809985a..e836efd98795 100644 > --- a/kernel/liveupdate/kexec_handover.c > +++ b/kernel/liveupdate/kexec_handover.c > @@ -357,6 +357,24 @@ int kho_radix_walk_tree(struct kho_radix_tree *tree, > } > EXPORT_SYMBOL_GPL(kho_radix_walk_tree); > > +/* For physically contiguous pages. */ > +static void kho_init_high_order_page(struct page *page, unsigned int order) > +{ > + unsigned long nr_pages = (1UL << 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 high-order blocks, tail pages get a page count of zero. */ > + for (unsigned long i = 1; i < nr_pages; i++) { > + set_page_count(page + i, 0); > + /* Clear each page's codetag to avoid accounting mismatch. */ > + clear_page_tag_ref(page + i); > + } That's sneaky... The patch _almost_ looks like pure code movement, but then adds this little change. I'm not saying this is intentionally sneaky or anything of the sort, but these kind of things are easy to miss during code movement and should get a patch of their own or at least be called out in the commit message. I don't know how page tags work, but IIRC when the change was originally added by Ran, he said that we don't need to clear the tag for tail pages. That held true for folios, does it not hold true for non-compound high-order pages? > +} > + > /* For physically contiguous 0-order pages. */ > static void kho_init_pages(struct page *page, unsigned long nr_pages) > { > @@ -369,16 +387,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_init_high_order_page(page, order); > > if (order > 0) > prep_compound_page(page, order); -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 1/2] kho: Introduce a helper to init high order pages 2026-08-12 10:54 ` Pratyush Yadav @ 2026-08-12 12:33 ` Pranjal Shrivastava 0 siblings, 0 replies; 12+ messages in thread From: Pranjal Shrivastava @ 2026-08-12 12:33 UTC (permalink / raw) To: Pratyush Yadav Cc: Mike Rapoport, Pasha Tatashin, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Wed, Aug 12, 2026 at 12:54:45PM +0200, Pratyush Yadav wrote: > On Mon, Aug 03 2026, Pranjal Shrivastava wrote: > > > The current KHO restoration logic assumes all multi-page blocks are > > split into independent 4KB pages. Break out a helper to prepare for > > supporting high-order non-compound pages. > > > > Extract kho_init_high_order_page() to handle the refcount pattern > > where only the head page is refcounted. Use the helper for folio > > restoration that requires a similar refcount logic. > > > > Reviewed-by: Samiullah Khawaja <skhawaja@google.com> > > Signed-off-by: Pranjal Shrivastava <praan@google.com> > > --- > > kernel/liveupdate/kexec_handover.c | 29 +++++++++++++++++++---------- > > 1 file changed, 19 insertions(+), 10 deletions(-) > > > > diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c > > index 4834a809985a..e836efd98795 100644 > > --- a/kernel/liveupdate/kexec_handover.c > > +++ b/kernel/liveupdate/kexec_handover.c > > @@ -357,6 +357,24 @@ int kho_radix_walk_tree(struct kho_radix_tree *tree, > > } > > EXPORT_SYMBOL_GPL(kho_radix_walk_tree); > > > > +/* For physically contiguous pages. */ > > +static void kho_init_high_order_page(struct page *page, unsigned int order) > > +{ > > + unsigned long nr_pages = (1UL << 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 high-order blocks, tail pages get a page count of zero. */ > > + for (unsigned long i = 1; i < nr_pages; i++) { > > + set_page_count(page + i, 0); > > + /* Clear each page's codetag to avoid accounting mismatch. */ > > + clear_page_tag_ref(page + i); > > + } > > That's sneaky... > > The patch _almost_ looks like pure code movement, but then adds this > little change. I'm not saying this is intentionally sneaky or anything > of the sort, but these kind of things are easy to miss during code > movement and should get a patch of their own or at least be called out > in the commit message. > > I don't know how page tags work, but IIRC when the change was originally > added by Ran, he said that we don't need to clear the tag for tail > pages. That held true for folios, does it not hold true for non-compound > high-order pages? > Hmm.. I added it here because I saw pgalloc_tag_add(..., 1 << order, ..); being called in the post_alloc_hook [1] but digging deeper I see it doesn't set a tag_ref on the tail pages for non-compound high-order pages (i.e. it doesn't loop over 1 << order pages) [2] We seem to clear tag refs which shouldn't be set in the first place, I'll remove the clear_page_tag_ref(page + i); in the tail loop. Thanks, Praan [1] https://elixir.bootlin.com/linux/v7.2-rc3/source/mm/page_alloc.c#L1861 [2] https://elixir.bootlin.com/linux/v7.2-rc3/source/mm/page_alloc.c#L1255 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages 2026-08-03 11:39 [PATCH v4 0/2] kho: support preserving high-order non-compound pages Pranjal Shrivastava 2026-08-03 11:39 ` [PATCH v4 1/2] kho: Introduce a helper to init high order pages Pranjal Shrivastava @ 2026-08-03 11:39 ` Pranjal Shrivastava 2026-08-12 11:10 ` Pratyush Yadav 2026-08-11 10:27 ` [PATCH v4 0/2] kho: support preserving high-order non-compound pages Mike Rapoport 2 siblings, 1 reply; 12+ messages in thread From: Pranjal Shrivastava @ 2026-08-03 11:39 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel, Pranjal Shrivastava The current KHO page preservation APIs (e.g. kho_preserve_pages) assume that multi-page blocks are split into independent 4KB pages during restoration. This is incompatible with high-order non-compound pages, such as DMA buffers, which must be restored with tail pages having a zero reference count. Introduce explicit preserve and restore APIs for high-order pages, which preserve and restore a high-order page block as a single unit, applying a refcount of 1 to the head page while leaving tail pages at 0. Rename the existing internal helper to __kho_restore_page() and consolidate the common restoration code into it. Signed-off-by: Pranjal Shrivastava <praan@google.com> --- include/linux/kexec_handover.h | 10 +++ kernel/liveupdate/kexec_handover.c | 98 ++++++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 8968c56d2d73..6e2c75b16209 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -22,6 +22,8 @@ bool is_kho_boot(void); int kho_preserve_folio(struct folio *folio); void kho_unpreserve_folio(struct folio *folio); +int kho_preserve_page(struct page *page, unsigned int order); +void kho_unpreserve_page(struct page *page, unsigned int order); int kho_preserve_pages(struct page *page, unsigned long nr_pages); void kho_unpreserve_pages(struct page *page, unsigned long nr_pages); int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation); @@ -30,6 +32,7 @@ void *kho_alloc_preserve(size_t size); void kho_unpreserve_free(void *mem); void kho_restore_free(void *mem); struct folio *kho_restore_folio(phys_addr_t phys); +struct page *kho_restore_page(phys_addr_t phys); struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages); void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); int kho_add_subtree(const char *name, void *blob, size_t size); @@ -65,6 +68,13 @@ static inline int kho_preserve_pages(struct page *page, unsigned int nr_pages) static inline void kho_unpreserve_pages(struct page *page, unsigned int nr_pages) { } +static inline int kho_preserve_page(struct page *page, unsigned int order) +{ + return -EOPNOTSUPP; +} + +static inline void kho_unpreserve_page(struct page *page, unsigned int order) { } + static inline int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation) { diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index e836efd98795..dd41d324c213 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -393,10 +393,9 @@ static void kho_init_folio(struct page *page, unsigned int order) prep_compound_page(page, order); } -static struct page *kho_restore_page(phys_addr_t phys, bool is_folio) +static struct page *__kho_restore_page(phys_addr_t phys, unsigned int *order) { struct page *page = pfn_to_online_page(PHYS_PFN(phys)); - unsigned long nr_pages; union kho_page_info info; if (!page) @@ -410,17 +409,14 @@ static struct page *kho_restore_page(phys_addr_t phys, bool is_folio) */ if (WARN_ON_ONCE(info.magic != KHO_PAGE_MAGIC)) return NULL; - nr_pages = (1 << info.order); /* Clear private to make sure later restores on this page error out. */ page->private = 0; + if (order) + *order = info.order; - if (is_folio) - kho_init_folio(page, info.order); - else - kho_init_pages(page, nr_pages); + adjust_managed_page_count(page, 1UL << info.order); - adjust_managed_page_count(page, nr_pages); return page; } @@ -432,12 +428,41 @@ static struct page *kho_restore_page(phys_addr_t phys, bool is_folio) */ struct folio *kho_restore_folio(phys_addr_t phys) { - struct page *page = kho_restore_page(phys, true); + unsigned int order; + struct page *page = __kho_restore_page(phys, &order); + + if (!page) + return NULL; + + kho_init_folio(page, order); - return page ? page_folio(page) : NULL; + return page_folio(page); } EXPORT_SYMBOL_GPL(kho_restore_folio); +/** + * kho_restore_page - restore a high-order page block. + * @phys: physical address of the first page. + * + * Restore a high-order page block that was preserved with + * kho_preserve_page(). + * + * Return: the head page on success, NULL on failure. + */ +struct page *kho_restore_page(phys_addr_t phys) +{ + unsigned int order; + struct page *page = __kho_restore_page(phys, &order); + + if (!page) + return NULL; + + kho_init_high_order_page(page, order); + + return page; +} +EXPORT_SYMBOL_GPL(kho_restore_page); + /** * kho_restore_pages - restore list of contiguous order 0 pages. * @phys: physical address of the first page. @@ -457,10 +482,13 @@ struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages) while (pfn < end_pfn) { const unsigned int order = min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn)); - struct page *page = kho_restore_page(PFN_PHYS(pfn), false); + unsigned int info_order; + struct page *page = __kho_restore_page(PFN_PHYS(pfn), &info_order); if (!page) return NULL; + + kho_init_pages(page, 1UL << info_order); pfn += 1 << order; } @@ -890,6 +918,51 @@ void kho_unpreserve_folio(struct folio *folio) } EXPORT_SYMBOL_GPL(kho_unpreserve_folio); +/** + * kho_preserve_page - preserve a high-order page block. + * @page: head page of the block. + * @order: order of the allocation. + * + * Instructs KHO to preserve a high-order contiguous allocation (like a DMA + * buffer) as a single unit. It must be restored using kho_restore_page() to + * ensure the tail pages are correctly initialized with a zero refcount. + * + * If a driver needs to split a block that has been preserved with this + * function, it must first unpreserve the block using kho_unpreserve_page(), + * perform the split, and then re-preserve the individual pages using + * kho_preserve_pages(). + * + * Return: 0 on success, error code on failure + */ +int kho_preserve_page(struct page *page, unsigned int order) +{ + struct kho_radix_tree *tree = &kho_out.radix_tree; + const unsigned long pfn = page_to_pfn(page); + + if (WARN_ON(kho_scratch_overlap(pfn << PAGE_SHIFT, PAGE_SIZE << order))) + return -EINVAL; + + return kho_radix_add_page(tree, pfn, order); +} +EXPORT_SYMBOL_GPL(kho_preserve_page); + +/** + * kho_unpreserve_page - unpreserve a high-order page block. + * @page: head page of the block. + * @order: order of the allocation. + * + * Instructs KHO to unpreserve a high-order block that was preserved by + * kho_preserve_page() before. + */ +void kho_unpreserve_page(struct page *page, unsigned int order) +{ + struct kho_radix_tree *tree = &kho_out.radix_tree; + const unsigned long pfn = page_to_pfn(page); + + kho_radix_del_page(tree, pfn, order); +} +EXPORT_SYMBOL_GPL(kho_unpreserve_page); + static unsigned int __kho_preserve_pages_order(unsigned long start_pfn, unsigned long end_pfn) { @@ -927,7 +1000,8 @@ static void __kho_unpreserve(struct kho_radix_tree *tree, * @nr_pages: number of pages. * * Preserve a contiguous list of order 0 pages. Must be restored using - * kho_restore_pages() to ensure the pages are restored properly as order 0. + * kho_restore_pages() to ensure the pages are restored properly as order 0 + * with each page having a reference count of 1 (split). * * Return: 0 on success, error code on failure */ -- 2.55.0.508.g3f0d502094-goog ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages 2026-08-03 11:39 ` [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages Pranjal Shrivastava @ 2026-08-12 11:10 ` Pratyush Yadav 2026-08-12 12:46 ` Pranjal Shrivastava 0 siblings, 1 reply; 12+ messages in thread From: Pratyush Yadav @ 2026-08-12 11:10 UTC (permalink / raw) To: Pranjal Shrivastava Cc: Mike Rapoport, Pasha Tatashin, Pratyush Yadav, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Mon, Aug 03 2026, Pranjal Shrivastava wrote: > The current KHO page preservation APIs (e.g. kho_preserve_pages) assume > that multi-page blocks are split into independent 4KB pages during > restoration. This is incompatible with high-order non-compound pages, > such as DMA buffers, which must be restored with tail pages having a > zero reference count. > > Introduce explicit preserve and restore APIs for high-order pages, > which preserve and restore a high-order page block as a single unit, > applying a refcount of 1 to the head page while leaving tail pages at 0. > Rename the existing internal helper to __kho_restore_page() and > consolidate the common restoration code into it. > > Signed-off-by: Pranjal Shrivastava <praan@google.com> The code here looks very convoluted TBH. I think it will be simpler to make kho_restore_page() only return non-compound pages. That is, it returns 0 or higher order non-compound page. Then kho_restore_pages() can call kho_restore_page() and then do split_page() on the page it got to turn it into 0-order pages. kho_restore_folio() can call kho_restore_page() and then do prep_compound_page() on the page it got. And then you expose kho_restore_page() to be used by DMA APIs to get non-compound high order pages directly. How does that sound? [...] -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages 2026-08-12 11:10 ` Pratyush Yadav @ 2026-08-12 12:46 ` Pranjal Shrivastava 2026-08-12 13:49 ` Pratyush Yadav 0 siblings, 1 reply; 12+ messages in thread From: Pranjal Shrivastava @ 2026-08-12 12:46 UTC (permalink / raw) To: Pratyush Yadav Cc: Mike Rapoport, Pasha Tatashin, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Wed, Aug 12, 2026 at 01:10:23PM +0200, Pratyush Yadav wrote: > On Mon, Aug 03 2026, Pranjal Shrivastava wrote: > > > The current KHO page preservation APIs (e.g. kho_preserve_pages) assume > > that multi-page blocks are split into independent 4KB pages during > > restoration. This is incompatible with high-order non-compound pages, > > such as DMA buffers, which must be restored with tail pages having a > > zero reference count. > > > > Introduce explicit preserve and restore APIs for high-order pages, > > which preserve and restore a high-order page block as a single unit, > > applying a refcount of 1 to the head page while leaving tail pages at 0. > > Rename the existing internal helper to __kho_restore_page() and > > consolidate the common restoration code into it. > > > > Signed-off-by: Pranjal Shrivastava <praan@google.com> > > The code here looks very convoluted TBH. I think it will be simpler to > make kho_restore_page() only return non-compound pages. That is, it > returns 0 or higher order non-compound page. > > Then kho_restore_pages() can call kho_restore_page() and then do > split_page() on the page it got to turn it into 0-order pages. > kho_restore_folio() can call kho_restore_page() and then do > prep_compound_page() on the page it got. > > And then you expose kho_restore_page() to be used by DMA APIs to get > non-compound high order pages directly. > > How does that sound? > I like the suggestion to use a single base primitive and mold it via split_page() and prep_compound_page(). However, To implement this, we'll need __kho_restore_page(phys, &order) as the internal base primitive because callers (like kho_restore_folio) need to retrieve the order from the KHO metadata to pass into prep_compound_page(), and a raw non-compound struct page doesn't store its order. By having __kho_restore_page() initialize the head_ref = 1 & all_tails =0 refcount pattern by default, all three public APIs can just wrap it and call the appropriate MM subsystem helpers. I'll spin v5 with this Thanks, Praan ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages 2026-08-12 12:46 ` Pranjal Shrivastava @ 2026-08-12 13:49 ` Pratyush Yadav 0 siblings, 0 replies; 12+ messages in thread From: Pratyush Yadav @ 2026-08-12 13:49 UTC (permalink / raw) To: Pranjal Shrivastava Cc: Pratyush Yadav, Mike Rapoport, Pasha Tatashin, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Wed, Aug 12 2026, Pranjal Shrivastava wrote: > On Wed, Aug 12, 2026 at 01:10:23PM +0200, Pratyush Yadav wrote: >> On Mon, Aug 03 2026, Pranjal Shrivastava wrote: >> >> > The current KHO page preservation APIs (e.g. kho_preserve_pages) assume >> > that multi-page blocks are split into independent 4KB pages during >> > restoration. This is incompatible with high-order non-compound pages, >> > such as DMA buffers, which must be restored with tail pages having a >> > zero reference count. >> > >> > Introduce explicit preserve and restore APIs for high-order pages, >> > which preserve and restore a high-order page block as a single unit, >> > applying a refcount of 1 to the head page while leaving tail pages at 0. >> > Rename the existing internal helper to __kho_restore_page() and >> > consolidate the common restoration code into it. >> > >> > Signed-off-by: Pranjal Shrivastava <praan@google.com> >> >> The code here looks very convoluted TBH. I think it will be simpler to >> make kho_restore_page() only return non-compound pages. That is, it >> returns 0 or higher order non-compound page. >> >> Then kho_restore_pages() can call kho_restore_page() and then do >> split_page() on the page it got to turn it into 0-order pages. >> kho_restore_folio() can call kho_restore_page() and then do >> prep_compound_page() on the page it got. >> >> And then you expose kho_restore_page() to be used by DMA APIs to get >> non-compound high order pages directly. >> >> How does that sound? >> > > I like the suggestion to use a single base primitive and mold it via > split_page() and prep_compound_page(). > > However, To implement this, we'll need __kho_restore_page(phys, &order) > as the internal base primitive because callers (like kho_restore_folio) > need to retrieve the order from the KHO metadata to pass into > prep_compound_page(), and a raw non-compound struct page doesn't store > its order. Oh, right. I didn't think of that. > > By having __kho_restore_page() initialize the head_ref = 1 & all_tails > =0 refcount pattern by default, all three public APIs can just wrap it > and call the appropriate MM subsystem helpers. I'll spin v5 with this Makes sense I think. -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/2] kho: support preserving high-order non-compound pages 2026-08-03 11:39 [PATCH v4 0/2] kho: support preserving high-order non-compound pages Pranjal Shrivastava 2026-08-03 11:39 ` [PATCH v4 1/2] kho: Introduce a helper to init high order pages Pranjal Shrivastava 2026-08-03 11:39 ` [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages Pranjal Shrivastava @ 2026-08-11 10:27 ` Mike Rapoport 2026-08-12 10:32 ` Pratyush Yadav 2 siblings, 1 reply; 12+ messages in thread From: Mike Rapoport @ 2026-08-11 10:27 UTC (permalink / raw) To: Pranjal Shrivastava Cc: Pasha Tatashin, Pratyush Yadav, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel Hi Pranjal, On Mon, Aug 03, 2026 at 11:39:41AM +0000, Pranjal Shrivastava wrote: > Introduction > ============ > This series is required for the ongoing effort to preserve DMA allocations > across KHO [1]. It addresses a fundamental mismatch between the current KHO > restoration logic and the physical reality of high-order buddy allocations. I skimmed through the patches, they look fine to me before the in-depth review :) But we are really close to the merge window, so we'll anyway need to reiterate after v7.3-rc1. > The Problem > =========== > The current KHO restore implementation treats all multi-page blocks as > split pages during restoration. Specifically, kho_restore_pages() > initializes every 4KB sub-page with a refcount of 1. > > However, many kernel subsystems, most notably the DMA allocator (via > dma_alloc_coherent), frequently return high-order non-compound pages. > In this state, only the head page carries a refcount of 1, while > all tail pages have a refcount of 0. This hints that these patches could be a part of the DMA preservation series, unless you expect other users of the new API. Generally, we don't merge new APIs without the users and if DMA preservation is the only user, it's better to fold these two patches there. -- Sincerely yours, Mike. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/2] kho: support preserving high-order non-compound pages 2026-08-11 10:27 ` [PATCH v4 0/2] kho: support preserving high-order non-compound pages Mike Rapoport @ 2026-08-12 10:32 ` Pratyush Yadav 2026-08-12 12:49 ` Pranjal Shrivastava 0 siblings, 1 reply; 12+ messages in thread From: Pratyush Yadav @ 2026-08-12 10:32 UTC (permalink / raw) To: Mike Rapoport Cc: Pranjal Shrivastava, Pasha Tatashin, Pratyush Yadav, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Tue, Aug 11 2026, Mike Rapoport wrote: > Hi Pranjal, > > On Mon, Aug 03, 2026 at 11:39:41AM +0000, Pranjal Shrivastava wrote: >> Introduction >> ============ >> This series is required for the ongoing effort to preserve DMA allocations >> across KHO [1]. It addresses a fundamental mismatch between the current KHO >> restoration logic and the physical reality of high-order buddy allocations. > > I skimmed through the patches, they look fine to me before the in-depth > review :) > > But we are really close to the merge window, so we'll anyway need to > reiterate after v7.3-rc1. > >> The Problem >> =========== >> The current KHO restore implementation treats all multi-page blocks as >> split pages during restoration. Specifically, kho_restore_pages() >> initializes every 4KB sub-page with a refcount of 1. >> >> However, many kernel subsystems, most notably the DMA allocator (via >> dma_alloc_coherent), frequently return high-order non-compound pages. >> In this state, only the head page carries a refcount of 1, while >> all tail pages have a refcount of 0. > > This hints that these patches could be a part of the DMA preservation > series, unless you expect other users of the new API. > > Generally, we don't merge new APIs without the users and if DMA > preservation is the only user, it's better to fold these two patches there. Makes sense I think. We can review the patches here, but then they can go in with the DMA series. -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/2] kho: support preserving high-order non-compound pages 2026-08-12 10:32 ` Pratyush Yadav @ 2026-08-12 12:49 ` Pranjal Shrivastava 2026-08-12 13:46 ` Pratyush Yadav 0 siblings, 1 reply; 12+ messages in thread From: Pranjal Shrivastava @ 2026-08-12 12:49 UTC (permalink / raw) To: Pratyush Yadav Cc: Mike Rapoport, Pasha Tatashin, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Wed, Aug 12, 2026 at 12:32:25PM +0200, Pratyush Yadav wrote: > On Tue, Aug 11 2026, Mike Rapoport wrote: > > > Hi Pranjal, > > > > On Mon, Aug 03, 2026 at 11:39:41AM +0000, Pranjal Shrivastava wrote: > >> Introduction > >> ============ > >> This series is required for the ongoing effort to preserve DMA allocations > >> across KHO [1]. It addresses a fundamental mismatch between the current KHO > >> restoration logic and the physical reality of high-order buddy allocations. > > > > I skimmed through the patches, they look fine to me before the in-depth > > review :) > > > > But we are really close to the merge window, so we'll anyway need to > > reiterate after v7.3-rc1. > > > >> The Problem > >> =========== > >> The current KHO restore implementation treats all multi-page blocks as > >> split pages during restoration. Specifically, kho_restore_pages() > >> initializes every 4KB sub-page with a refcount of 1. > >> > >> However, many kernel subsystems, most notably the DMA allocator (via > >> dma_alloc_coherent), frequently return high-order non-compound pages. > >> In this state, only the head page carries a refcount of 1, while > >> all tail pages have a refcount of 0. > > > > This hints that these patches could be a part of the DMA preservation > > series, unless you expect other users of the new API. > > > > Generally, we don't merge new APIs without the users and if DMA > > preservation is the only user, it's better to fold these two patches there. > > Makes sense I think. We can review the patches here, but then they can > go in with the DMA series. > So.. IIUC, I'll post a v5 here as a standalone series till we get consensus, and finally the reviewed patches can be folded with the DMA series? Thanks, Praan ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/2] kho: support preserving high-order non-compound pages 2026-08-12 12:49 ` Pranjal Shrivastava @ 2026-08-12 13:46 ` Pratyush Yadav 0 siblings, 0 replies; 12+ messages in thread From: Pratyush Yadav @ 2026-08-12 13:46 UTC (permalink / raw) To: Pranjal Shrivastava Cc: Pratyush Yadav, Mike Rapoport, Pasha Tatashin, Alexander Graf, Samiullah Khawaja, David Matlack, kexec, linux-mm, linux-kernel On Wed, Aug 12 2026, Pranjal Shrivastava wrote: > On Wed, Aug 12, 2026 at 12:32:25PM +0200, Pratyush Yadav wrote: >> On Tue, Aug 11 2026, Mike Rapoport wrote: >> >> > Hi Pranjal, >> > >> > On Mon, Aug 03, 2026 at 11:39:41AM +0000, Pranjal Shrivastava wrote: >> >> Introduction >> >> ============ >> >> This series is required for the ongoing effort to preserve DMA allocations >> >> across KHO [1]. It addresses a fundamental mismatch between the current KHO >> >> restoration logic and the physical reality of high-order buddy allocations. >> > >> > I skimmed through the patches, they look fine to me before the in-depth >> > review :) >> > >> > But we are really close to the merge window, so we'll anyway need to >> > reiterate after v7.3-rc1. >> > >> >> The Problem >> >> =========== >> >> The current KHO restore implementation treats all multi-page blocks as >> >> split pages during restoration. Specifically, kho_restore_pages() >> >> initializes every 4KB sub-page with a refcount of 1. >> >> >> >> However, many kernel subsystems, most notably the DMA allocator (via >> >> dma_alloc_coherent), frequently return high-order non-compound pages. >> >> In this state, only the head page carries a refcount of 1, while >> >> all tail pages have a refcount of 0. >> > >> > This hints that these patches could be a part of the DMA preservation >> > series, unless you expect other users of the new API. >> > >> > Generally, we don't merge new APIs without the users and if DMA >> > preservation is the only user, it's better to fold these two patches there. >> >> Makes sense I think. We can review the patches here, but then they can >> go in with the DMA series. >> > > So.. IIUC, I'll post a v5 here as a standalone series till we get > consensus, and finally the reviewed patches can be folded with the DMA > series? That sounds good to me at least. -- Regards, Pratyush Yadav ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-08-12 13:49 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-03 11:39 [PATCH v4 0/2] kho: support preserving high-order non-compound pages Pranjal Shrivastava 2026-08-03 11:39 ` [PATCH v4 1/2] kho: Introduce a helper to init high order pages Pranjal Shrivastava 2026-08-12 10:54 ` Pratyush Yadav 2026-08-12 12:33 ` Pranjal Shrivastava 2026-08-03 11:39 ` [PATCH v4 2/2] kho: Introduce preserve/restore APIs for high-order pages Pranjal Shrivastava 2026-08-12 11:10 ` Pratyush Yadav 2026-08-12 12:46 ` Pranjal Shrivastava 2026-08-12 13:49 ` Pratyush Yadav 2026-08-11 10:27 ` [PATCH v4 0/2] kho: support preserving high-order non-compound pages Mike Rapoport 2026-08-12 10:32 ` Pratyush Yadav 2026-08-12 12:49 ` Pranjal Shrivastava 2026-08-12 13:46 ` Pratyush Yadav
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.