[RFC PATCH 2/4] kho: Detect preserved page types

Pranjal Shrivastava praan at google.com
Thu Jul 2 19:08:30 PDT 2026


Detect page types in kho_preserve_pages() by peeking into the refcount
of the second page in each block of order > 0. If the second page has
a non-zero reference count, it indicates that the block has been split.
Otherwise, treated it as a contiguous, unsplit block.

Since the page type is now part of the radix tree key, update the
unpreserve path to use the same detection logic to ensure it can
correctly locate and delete existing entries.

Signed-off-by: Pranjal Shrivastava <praan at google.com>
---
 kernel/liveupdate/kexec_handover.c | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index f829ffdd00f4..d6e81f72fe5d 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -918,15 +918,29 @@ static unsigned int __kho_preserve_pages_order(unsigned long start_pfn,
 	return order;
 }
 
+static bool kho_is_page_split(unsigned long pfn, unsigned int order)
+{
+	/*
+	 * If the refcount of the second page is non-zero, this block
+	 * has been split.
+	 */
+	if (order > 0 && page_ref_count(pfn_to_page(pfn + 1)) != 0)
+		return true;
+
+	return false;
+}
+
 static void __kho_unpreserve(struct kho_radix_tree *tree,
 			     unsigned long pfn, unsigned long end_pfn)
 {
-	unsigned int order;
-
 	while (pfn < end_pfn) {
-		order = __kho_preserve_pages_order(pfn, end_pfn);
+		unsigned int order = __kho_preserve_pages_order(pfn, end_pfn);
+		enum kho_page_type type;
 
-		kho_radix_del_page(tree, pfn, order, KHO_PAGE_CONTIG);
+		type = kho_is_page_split(pfn, order) ? KHO_PAGE_SPLIT :
+						       KHO_PAGE_CONTIG;
+
+		kho_radix_del_page(tree, pfn, order, type);
 
 		pfn += 1 << order;
 	}
@@ -958,8 +972,12 @@ int kho_preserve_pages(struct page *page, unsigned long nr_pages)
 
 	while (pfn < end_pfn) {
 		unsigned int order = __kho_preserve_pages_order(pfn, end_pfn);
+		enum kho_page_type type;
+
+		type = kho_is_page_split(pfn, order) ? KHO_PAGE_SPLIT :
+						       KHO_PAGE_CONTIG;
 
-		err = kho_radix_add_page(tree, pfn, order, KHO_PAGE_CONTIG);
+		err = kho_radix_add_page(tree, pfn, order, type);
 		if (err) {
 			failed_pfn = pfn;
 			break;
-- 
2.55.0.rc0.799.gd6f94ed593-goog




More information about the kexec mailing list