Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kho: add interfaces to unpreserve folios, page ranges, and vmalloc

Allow users of KHO to cancel the previous preservation by adding the
necessary interfaces to unpreserve folio, pages, and vmallocs.

Link: https://lkml.kernel.org/r/20251101142325.1326536-4-pasha.tatashin@soleen.com
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Alexander Graf <graf@amazon.com>
Cc: Changyuan Lyu <changyuanl@google.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Simon Horman <horms@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Zhu Yanjun <yanjun.zhu@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Pasha Tatashin and committed by
Andrew Morton
36f8f7ef 70f91330

+110 -14
+18
include/linux/kexec_handover.h
··· 43 43 bool is_kho_boot(void); 44 44 45 45 int kho_preserve_folio(struct folio *folio); 46 + int kho_unpreserve_folio(struct folio *folio); 46 47 int kho_preserve_pages(struct page *page, unsigned int nr_pages); 48 + int kho_unpreserve_pages(struct page *page, unsigned int nr_pages); 47 49 int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation); 50 + int kho_unpreserve_vmalloc(struct kho_vmalloc *preservation); 48 51 struct folio *kho_restore_folio(phys_addr_t phys); 49 52 struct page *kho_restore_pages(phys_addr_t phys, unsigned int nr_pages); 50 53 void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); ··· 75 72 return -EOPNOTSUPP; 76 73 } 77 74 75 + static inline int kho_unpreserve_folio(struct folio *folio) 76 + { 77 + return -EOPNOTSUPP; 78 + } 79 + 78 80 static inline int kho_preserve_pages(struct page *page, unsigned int nr_pages) 81 + { 82 + return -EOPNOTSUPP; 83 + } 84 + 85 + static inline int kho_unpreserve_pages(struct page *page, unsigned int nr_pages) 79 86 { 80 87 return -EOPNOTSUPP; 81 88 } 82 89 83 90 static inline int kho_preserve_vmalloc(void *ptr, 84 91 struct kho_vmalloc *preservation) 92 + { 93 + return -EOPNOTSUPP; 94 + } 95 + 96 + static inline int kho_unpreserve_vmalloc(struct kho_vmalloc *preservation) 85 97 { 86 98 return -EOPNOTSUPP; 87 99 }
+92 -14
kernel/kexec_handover.c
··· 157 157 return no_free_ptr(elm); 158 158 } 159 159 160 - static void __kho_unpreserve(struct kho_mem_track *track, unsigned long pfn, 161 - unsigned long end_pfn) 160 + static void __kho_unpreserve_order(struct kho_mem_track *track, unsigned long pfn, 161 + unsigned int order) 162 162 { 163 163 struct kho_mem_phys_bits *bits; 164 164 struct kho_mem_phys *physxa; 165 + const unsigned long pfn_high = pfn >> order; 166 + 167 + physxa = xa_load(&track->orders, order); 168 + if (WARN_ON_ONCE(!physxa)) 169 + return; 170 + 171 + bits = xa_load(&physxa->phys_bits, pfn_high / PRESERVE_BITS); 172 + if (WARN_ON_ONCE(!bits)) 173 + return; 174 + 175 + clear_bit(pfn_high % PRESERVE_BITS, bits->preserve); 176 + } 177 + 178 + static void __kho_unpreserve(struct kho_mem_track *track, unsigned long pfn, 179 + unsigned long end_pfn) 180 + { 181 + unsigned int order; 165 182 166 183 while (pfn < end_pfn) { 167 - const unsigned int order = 168 - min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn)); 169 - const unsigned long pfn_high = pfn >> order; 184 + order = min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn)); 170 185 171 - physxa = xa_load(&track->orders, order); 172 - if (WARN_ON_ONCE(!physxa)) 173 - return; 174 - 175 - bits = xa_load(&physxa->phys_bits, pfn_high / PRESERVE_BITS); 176 - if (WARN_ON_ONCE(!bits)) 177 - return; 178 - 179 - clear_bit(pfn_high % PRESERVE_BITS, bits->preserve); 186 + __kho_unpreserve_order(track, pfn, order); 180 187 181 188 pfn += 1 << order; 182 189 } ··· 753 746 EXPORT_SYMBOL_GPL(kho_preserve_folio); 754 747 755 748 /** 749 + * kho_unpreserve_folio - unpreserve a folio. 750 + * @folio: folio to unpreserve. 751 + * 752 + * Instructs KHO to unpreserve a folio that was preserved by 753 + * kho_preserve_folio() before. The provided @folio (pfn and order) 754 + * must exactly match a previously preserved folio. 755 + * 756 + * Return: 0 on success, error code on failure 757 + */ 758 + int kho_unpreserve_folio(struct folio *folio) 759 + { 760 + const unsigned long pfn = folio_pfn(folio); 761 + const unsigned int order = folio_order(folio); 762 + struct kho_mem_track *track = &kho_out.track; 763 + 764 + if (kho_out.finalized) 765 + return -EBUSY; 766 + 767 + __kho_unpreserve_order(track, pfn, order); 768 + return 0; 769 + } 770 + EXPORT_SYMBOL_GPL(kho_unpreserve_folio); 771 + 772 + /** 756 773 * kho_preserve_pages - preserve contiguous pages across kexec 757 774 * @page: first page in the list. 758 775 * @nr_pages: number of pages. ··· 819 788 return err; 820 789 } 821 790 EXPORT_SYMBOL_GPL(kho_preserve_pages); 791 + 792 + /** 793 + * kho_unpreserve_pages - unpreserve contiguous pages. 794 + * @page: first page in the list. 795 + * @nr_pages: number of pages. 796 + * 797 + * Instructs KHO to unpreserve @nr_pages contiguous pages starting from @page. 798 + * This must be called with the same @page and @nr_pages as the corresponding 799 + * kho_preserve_pages() call. Unpreserving arbitrary sub-ranges of larger 800 + * preserved blocks is not supported. 801 + * 802 + * Return: 0 on success, error code on failure 803 + */ 804 + int kho_unpreserve_pages(struct page *page, unsigned int nr_pages) 805 + { 806 + struct kho_mem_track *track = &kho_out.track; 807 + const unsigned long start_pfn = page_to_pfn(page); 808 + const unsigned long end_pfn = start_pfn + nr_pages; 809 + 810 + if (kho_out.finalized) 811 + return -EBUSY; 812 + 813 + __kho_unpreserve(track, start_pfn, end_pfn); 814 + 815 + return 0; 816 + } 817 + EXPORT_SYMBOL_GPL(kho_unpreserve_pages); 822 818 823 819 struct kho_vmalloc_hdr { 824 820 DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *); ··· 1007 949 return err; 1008 950 } 1009 951 EXPORT_SYMBOL_GPL(kho_preserve_vmalloc); 952 + 953 + /** 954 + * kho_unpreserve_vmalloc - unpreserve memory allocated with vmalloc() 955 + * @preservation: preservation metadata returned by kho_preserve_vmalloc() 956 + * 957 + * Instructs KHO to unpreserve the area in vmalloc address space that was 958 + * previously preserved with kho_preserve_vmalloc(). 959 + * 960 + * Return: 0 on success, error code on failure 961 + */ 962 + int kho_unpreserve_vmalloc(struct kho_vmalloc *preservation) 963 + { 964 + if (kho_out.finalized) 965 + return -EBUSY; 966 + 967 + kho_vmalloc_free_chunks(preservation); 968 + 969 + return 0; 970 + } 971 + EXPORT_SYMBOL_GPL(kho_unpreserve_vmalloc); 1010 972 1011 973 /** 1012 974 * kho_restore_vmalloc - recreates and populates an area in vmalloc address