On Tue, Oct 21, 2025 at 08:57:16PM -0400, Pasha Tatashin wrote:
Allow users of KHO to cancel the previous preservation by adding the necessary interfaces to unpreserve folio and pages.
Signed-off-by: Pasha Tatashin pasha.tatashin@soleen.com
Reviewed-by: Mike Rapoport (Microsoft) rppt@kernel.org
include/linux/kexec_handover.h | 12 +++++ kernel/kexec_handover.c | 85 ++++++++++++++++++++++++++++------ 2 files changed, 84 insertions(+), 13 deletions(-)
diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 2faf290803ce..4ba145713838 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -43,7 +43,9 @@ bool kho_is_enabled(void); bool is_kho_boot(void); int kho_preserve_folio(struct folio *folio); +int kho_unpreserve_folio(struct folio *folio); int kho_preserve_pages(struct page *page, unsigned int nr_pages); +int kho_unpreserve_pages(struct page *page, unsigned int nr_pages); int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation); struct folio *kho_restore_folio(phys_addr_t phys); struct page *kho_restore_pages(phys_addr_t phys, unsigned int nr_pages); @@ -76,11 +78,21 @@ static inline int kho_preserve_folio(struct folio *folio) return -EOPNOTSUPP; } +static inline int kho_unpreserve_folio(struct folio *folio) +{
- return -EOPNOTSUPP;
+}
static inline int kho_preserve_pages(struct page *page, unsigned int nr_pages) { return -EOPNOTSUPP; } +static inline int kho_unpreserve_pages(struct page *page, unsigned int nr_pages) +{
- return -EOPNOTSUPP;
+}
static inline int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation) { diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c index 0a4234269fe5..8412897385ad 100644 --- a/kernel/kexec_handover.c +++ b/kernel/kexec_handover.c @@ -157,26 +157,33 @@ static void *xa_load_or_alloc(struct xarray *xa, unsigned long index) return no_free_ptr(elm); } -static void __kho_unpreserve(struct kho_mem_track *track, unsigned long pfn,
unsigned long end_pfn)+static void __kho_unpreserve_order(struct kho_mem_track *track, unsigned long pfn,
unsigned int order){ struct kho_mem_phys_bits *bits; struct kho_mem_phys *physxa;
- const unsigned long pfn_high = pfn >> order;
- while (pfn < end_pfn) {
const unsigned int order =min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));const unsigned long pfn_high = pfn >> order;
- physxa = xa_load(&track->orders, order);
- if (!physxa)
return;- bits = xa_load(&physxa->phys_bits, pfn_high / PRESERVE_BITS);
- if (!bits)
return;
physxa = xa_load(&track->orders, order);if (!physxa)continue;
- clear_bit(pfn_high % PRESERVE_BITS, bits->preserve);
+}
+static void __kho_unpreserve(struct kho_mem_track *track, unsigned long pfn,
unsigned long end_pfn)+{
- unsigned int order;
bits = xa_load(&physxa->phys_bits, pfn_high / PRESERVE_BITS);if (!bits)continue;
- while (pfn < end_pfn) {
order = min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));
clear_bit(pfn_high % PRESERVE_BITS, bits->preserve);
__kho_unpreserve_order(track, pfn, order);pfn += 1 << order; } @@ -749,6 +756,30 @@ int kho_preserve_folio(struct folio *folio) } EXPORT_SYMBOL_GPL(kho_preserve_folio); +/**
- kho_unpreserve_folio - unpreserve a folio.
- @folio: folio to unpreserve.
- Instructs KHO to unpreserve a folio that was preserved by
- kho_preserve_folio() before. The provided @folio (pfn and order)
- must exactly match a previously preserved folio.
- Return: 0 on success, error code on failure
- */
+int kho_unpreserve_folio(struct folio *folio) +{
- const unsigned long pfn = folio_pfn(folio);
- const unsigned int order = folio_order(folio);
- struct kho_mem_track *track = &kho_out.track;
- if (kho_out.finalized)
return -EBUSY;- __kho_unpreserve_order(track, pfn, order);
- return 0;
+} +EXPORT_SYMBOL_GPL(kho_unpreserve_folio);
/**
- kho_preserve_pages - preserve contiguous pages across kexec
- @page: first page in the list.
@@ -793,6 +824,34 @@ int kho_preserve_pages(struct page *page, unsigned int nr_pages) } EXPORT_SYMBOL_GPL(kho_preserve_pages); +/**
- kho_unpreserve_pages - unpreserve contiguous pages.
- @page: first page in the list.
- @nr_pages: number of pages.
- Instructs KHO to unpreserve @nr_pages contigious pages starting from @page.
- This call must exactly match a granularity at which memory was originally
- preserved by kho_preserve_pages, call with the same @page and
- @nr_pages). Unpreserving arbitrary sub-ranges of larger preserved blocks is
- not supported.
- Return: 0 on success, error code on failure
- */
+int kho_unpreserve_pages(struct page *page, unsigned int nr_pages) +{
- struct kho_mem_track *track = &kho_out.track;
- const unsigned long start_pfn = page_to_pfn(page);
- const unsigned long end_pfn = start_pfn + nr_pages;
- if (kho_out.finalized)
return -EBUSY;- __kho_unpreserve(track, start_pfn, end_pfn);
- return 0;
+} +EXPORT_SYMBOL_GPL(kho_unpreserve_pages);
struct kho_vmalloc_hdr { DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *); }; -- 2.51.0.915.g61a8936c21-goog