]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
kho: fix order calculation for kho_unpreserve_pages()
authorPratyush Yadav (Google) <pratyush@kernel.org>
Tue, 19 May 2026 13:33:30 +0000 (15:33 +0200)
committerMike Rapoport (Microsoft) <rppt@kernel.org>
Tue, 26 May 2026 08:01:49 +0000 (11:01 +0300)
Commit 91e74fa8b1bc ("kho: make sure preservations do not span multiple
NUMA nodes") made sure preservations from kho_preserve_pages() do not
span multiple NUMA nodes. If they do, the order is reduced and tried
again.

The same logic was not implemented for kho_unpreserve_pages(). This can
result in unpreserve calculating a different order than preserve, and
thus not actually unpreserving the pages.

Fix this by moving the order calculation logic to
__kho_preserve_pages_order() and use it from both preserve and
unpreserve paths.

Move __kho_unpreserve() down to avoid having a forward declaration. Its
users are further down in the file anyway. Also, it results in grouping
for all the page-level preservation and unpreservation functions. This
unfortunately makes the diff hard to read, but the main change in
__kho_unpreserve() is to call __kho_preserve_pages_order() instead of
open-coding the order calculation.

Fixes: 91e74fa8b1bc ("kho: make sure preservations do not span multiple NUMA nodes")
Cc: stable@vger.kernel.org
Signed-off-by: Pratyush Yadav (Google) <pratyush@kernel.org>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Link: https://patch.msgid.link/20260519133332.2498092-1-pratyush@kernel.org
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
kernel/liveupdate/kexec_handover.c

index 2592f7ca16e2e34f4e454e80ae97b477f46a2eaf..1b592d86dc4898858adfc35b9dfa2ae551acabf3 100644 (file)
@@ -357,20 +357,6 @@ int kho_radix_walk_tree(struct kho_radix_tree *tree,
 }
 EXPORT_SYMBOL_GPL(kho_radix_walk_tree);
 
-static void __kho_unpreserve(struct kho_radix_tree *tree,
-                            unsigned long pfn, unsigned long end_pfn)
-{
-       unsigned int order;
-
-       while (pfn < end_pfn) {
-               order = min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));
-
-               kho_radix_del_page(tree, pfn, order);
-
-               pfn += 1 << order;
-       }
-}
-
 /* For physically contiguous 0-order pages. */
 static void kho_init_pages(struct page *page, unsigned long nr_pages)
 {
@@ -860,6 +846,37 @@ void kho_unpreserve_folio(struct folio *folio)
 }
 EXPORT_SYMBOL_GPL(kho_unpreserve_folio);
 
+static unsigned int __kho_preserve_pages_order(unsigned long start_pfn,
+                                              unsigned long end_pfn)
+{
+       unsigned int order = min(count_trailing_zeros(start_pfn),
+                                ilog2(end_pfn - start_pfn));
+
+       /*
+        * Make sure all the pages in a single preservation are in the same NUMA
+        * node. The restore machinery can not cope with a preservation spanning
+        * multiple NUMA nodes.
+        */
+       while (pfn_to_nid(start_pfn) != pfn_to_nid(start_pfn + (1UL << order) - 1))
+               order--;
+
+       return order;
+}
+
+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);
+
+               kho_radix_del_page(tree, pfn, order);
+
+               pfn += 1 << order;
+       }
+}
+
 /**
  * kho_preserve_pages - preserve contiguous pages across kexec
  * @page: first page in the list.
@@ -885,16 +902,7 @@ int kho_preserve_pages(struct page *page, unsigned long nr_pages)
        }
 
        while (pfn < end_pfn) {
-               unsigned int order =
-                       min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));
-
-               /*
-                * Make sure all the pages in a single preservation are in the
-                * same NUMA node. The restore machinery can not cope with a
-                * preservation spanning multiple NUMA nodes.
-                */
-               while (pfn_to_nid(pfn) != pfn_to_nid(pfn + (1UL << order) - 1))
-                       order--;
+               unsigned int order = __kho_preserve_pages_order(pfn, end_pfn);
 
                err = kho_radix_add_page(tree, pfn, order);
                if (err) {