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: introduce high-level memory allocation API

Currently, clients of KHO must manually allocate memory (e.g., via
alloc_pages), calculate the page order, and explicitly call
kho_preserve_folio(). Similarly, cleanup requires separate calls to
unpreserve and free the memory.

Introduce a high-level API to streamline this common pattern:

- kho_alloc_preserve(size): Allocates physically contiguous, zeroed
memory and immediately marks it for preservation.
- kho_unpreserve_free(ptr): Unpreserves and frees the memory
in the current kernel.
- kho_restore_free(ptr): Restores the struct page state of
preserved memory in the new kernel and immediately frees it to the
page allocator.

[pasha.tatashin@soleen.com: build fixes]
Link: https://lkml.kernel.org/r/CA+CK2bBgXDhrHwTVgxrw7YTQ-0=LgW0t66CwPCgG=C85ftz4zw@mail.gmail.com
Link: https://lkml.kernel.org/r/20251114190002.3311679-4-pasha.tatashin@soleen.com
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Pratyush Yadav <pratyush@kernel.org>
Cc: Alexander Graf <graf@amazon.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Baoquan He <bhe@redhat.com>
Cc: Coiby Xu <coxu@redhat.com>
Cc: Dave Vasilevsky <dave@vasilevsky.ca>
Cc: Eric Biggers <ebiggers@google.com>
Cc: Kees Cook <kees@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Pasha Tatashin and committed by
Andrew Morton
4c205677 8c3819f6

+102 -7
+15 -7
include/linux/kexec_handover.h
··· 2 2 #ifndef LINUX_KEXEC_HANDOVER_H 3 3 #define LINUX_KEXEC_HANDOVER_H 4 4 5 - #include <linux/types.h> 5 + #include <linux/err.h> 6 6 #include <linux/errno.h> 7 + #include <linux/types.h> 7 8 8 9 struct kho_scratch { 9 10 phys_addr_t addr; ··· 49 48 int kho_unpreserve_pages(struct page *page, unsigned int nr_pages); 50 49 int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation); 51 50 int kho_unpreserve_vmalloc(struct kho_vmalloc *preservation); 51 + void *kho_alloc_preserve(size_t size); 52 + void kho_unpreserve_free(void *mem); 53 + void kho_restore_free(void *mem); 52 54 struct folio *kho_restore_folio(phys_addr_t phys); 53 55 struct page *kho_restore_pages(phys_addr_t phys, unsigned int nr_pages); 54 56 void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); ··· 105 101 return -EOPNOTSUPP; 106 102 } 107 103 104 + static inline void *kho_alloc_preserve(size_t size) 105 + { 106 + return ERR_PTR(-EOPNOTSUPP); 107 + } 108 + 109 + static inline void kho_unpreserve_free(void *mem) { } 110 + static inline void kho_restore_free(void *mem) { } 111 + 108 112 static inline struct folio *kho_restore_folio(phys_addr_t phys) 109 113 { 110 114 return NULL; ··· 134 122 return -EOPNOTSUPP; 135 123 } 136 124 137 - static inline void kho_remove_subtree(void *fdt) 138 - { 139 - } 125 + static inline void kho_remove_subtree(void *fdt) { } 140 126 141 127 static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys) 142 128 { 143 129 return -EOPNOTSUPP; 144 130 } 145 131 146 - static inline void kho_memory_init(void) 147 - { 148 - } 132 + static inline void kho_memory_init(void) { } 149 133 150 134 static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, 151 135 phys_addr_t scratch_phys, u64 scratch_len)
+87
kernel/liveupdate/kexec_handover.c
··· 4 4 * Copyright (C) 2023 Alexander Graf <graf@amazon.com> 5 5 * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport <rppt@kernel.org> 6 6 * Copyright (C) 2025 Google LLC, Changyuan Lyu <changyuanl@google.com> 7 + * Copyright (C) 2025 Pasha Tatashin <pasha.tatashin@soleen.com> 7 8 */ 8 9 9 10 #define pr_fmt(fmt) "KHO: " fmt ··· 1117 1116 return NULL; 1118 1117 } 1119 1118 EXPORT_SYMBOL_GPL(kho_restore_vmalloc); 1119 + 1120 + /** 1121 + * kho_alloc_preserve - Allocate, zero, and preserve memory. 1122 + * @size: The number of bytes to allocate. 1123 + * 1124 + * Allocates a physically contiguous block of zeroed pages that is large 1125 + * enough to hold @size bytes. The allocated memory is then registered with 1126 + * KHO for preservation across a kexec. 1127 + * 1128 + * Note: The actual allocated size will be rounded up to the nearest 1129 + * power-of-two page boundary. 1130 + * 1131 + * @return A virtual pointer to the allocated and preserved memory on success, 1132 + * or an ERR_PTR() encoded error on failure. 1133 + */ 1134 + void *kho_alloc_preserve(size_t size) 1135 + { 1136 + struct folio *folio; 1137 + int order, ret; 1138 + 1139 + if (!size) 1140 + return ERR_PTR(-EINVAL); 1141 + 1142 + order = get_order(size); 1143 + if (order > MAX_PAGE_ORDER) 1144 + return ERR_PTR(-E2BIG); 1145 + 1146 + folio = folio_alloc(GFP_KERNEL | __GFP_ZERO, order); 1147 + if (!folio) 1148 + return ERR_PTR(-ENOMEM); 1149 + 1150 + ret = kho_preserve_folio(folio); 1151 + if (ret) { 1152 + folio_put(folio); 1153 + return ERR_PTR(ret); 1154 + } 1155 + 1156 + return folio_address(folio); 1157 + } 1158 + EXPORT_SYMBOL_GPL(kho_alloc_preserve); 1159 + 1160 + /** 1161 + * kho_unpreserve_free - Unpreserve and free memory. 1162 + * @mem: Pointer to the memory allocated by kho_alloc_preserve(). 1163 + * 1164 + * Unregisters the memory from KHO preservation and frees the underlying 1165 + * pages back to the system. This function should be called to clean up 1166 + * memory allocated with kho_alloc_preserve(). 1167 + */ 1168 + void kho_unpreserve_free(void *mem) 1169 + { 1170 + struct folio *folio; 1171 + 1172 + if (!mem) 1173 + return; 1174 + 1175 + folio = virt_to_folio(mem); 1176 + WARN_ON_ONCE(kho_unpreserve_folio(folio)); 1177 + folio_put(folio); 1178 + } 1179 + EXPORT_SYMBOL_GPL(kho_unpreserve_free); 1180 + 1181 + /** 1182 + * kho_restore_free - Restore and free memory after kexec. 1183 + * @mem: Pointer to the memory (in the new kernel's address space) 1184 + * that was allocated by the old kernel. 1185 + * 1186 + * This function is intended to be called in the new kernel (post-kexec) 1187 + * to take ownership of and free a memory region that was preserved by the 1188 + * old kernel using kho_alloc_preserve(). 1189 + * 1190 + * It first restores the pages from KHO (using their physical address) 1191 + * and then frees the pages back to the new kernel's page allocator. 1192 + */ 1193 + void kho_restore_free(void *mem) 1194 + { 1195 + struct folio *folio; 1196 + 1197 + if (!mem) 1198 + return; 1199 + 1200 + folio = kho_restore_folio(__pa(mem)); 1201 + if (!WARN_ON(!folio)) 1202 + folio_put(folio); 1203 + } 1204 + EXPORT_SYMBOL_GPL(kho_restore_free); 1120 1205 1121 1206 static void __kho_abort(void) 1122 1207 {