summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/kexec_handover.h31
-rw-r--r--include/linux/kho/abi/kexec_handover.h9
-rw-r--r--include/linux/kho_radix_tree.h60
-rw-r--r--include/linux/liveupdate.h22
-rw-r--r--include/linux/memblock.h23
5 files changed, 95 insertions, 50 deletions
diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h
index 8968c56d2d73..46de86dc343e 100644
--- a/include/linux/kexec_handover.h
+++ b/include/linux/kexec_handover.h
@@ -5,11 +5,8 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/types.h>
-
-struct kho_scratch {
- phys_addr_t addr;
- phys_addr_t size;
-};
+#include <linux/mm.h>
+#include <asm-generic/kexec_handover.h>
struct kho_vmalloc;
@@ -37,9 +34,20 @@ void kho_remove_subtree(void *blob);
int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size);
void kho_memory_init(void);
+void kho_memory_init_early(void);
void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
u64 scratch_len);
+
+bool kho_scratch_overlap(phys_addr_t phys, size_t size);
+
+static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
+ enum migratetype mt)
+{
+ if (kho_scratch_overlap(PFN_PHYS(pfn), pageblock_nr_pages << PAGE_SHIFT))
+ return MIGRATE_CMA;
+ return mt;
+}
#else
static inline bool kho_is_enabled(void)
{
@@ -112,10 +120,23 @@ static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys,
static inline void kho_memory_init(void) { }
+static inline void kho_memory_init_early(void) { }
+
static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
phys_addr_t scratch_phys, u64 scratch_len)
{
}
+
+static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
+{
+ return false;
+}
+
+static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
+ enum migratetype mt)
+{
+ return mt;
+}
#endif /* CONFIG_KEXEC_HANDOVER */
#endif /* LINUX_KEXEC_HANDOVER_H */
diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
index 5e2eb8519bda..2f4fb9c63942 100644
--- a/include/linux/kho/abi/kexec_handover.h
+++ b/include/linux/kho/abi/kexec_handover.h
@@ -257,11 +257,8 @@ struct kho_vmalloc {
* memory. These constants govern the indexing, sizing, and depth of the tree.
*/
enum kho_radix_consts {
- /*
- * The bit position of the order bit (and also the length of the
- * shifted physical address) for an order-0 page.
- */
- KHO_ORDER_0_LOG2 = 64 - PAGE_SHIFT,
+ /* Need to store the PFN, plus one bit for order. */
+ KHO_RADIX_KEY_WIDTH = 64 - PAGE_SHIFT + 1,
/* Size of the table in kho_radix_node, in log2 */
KHO_TABLE_SIZE_LOG2 = const_ilog2(PAGE_SIZE / sizeof(phys_addr_t)),
@@ -274,7 +271,7 @@ enum kho_radix_consts {
* and 1 bitmap level.
*/
KHO_TREE_MAX_DEPTH =
- DIV_ROUND_UP(KHO_ORDER_0_LOG2 - KHO_BITMAP_SIZE_LOG2 + 1,
+ DIV_ROUND_UP(KHO_RADIX_KEY_WIDTH - KHO_BITMAP_SIZE_LOG2,
KHO_TABLE_SIZE_LOG2) + 1,
};
diff --git a/include/linux/kho_radix_tree.h b/include/linux/kho_radix_tree.h
index 84e918b96e53..fcd69639721b 100644
--- a/include/linux/kho_radix_tree.h
+++ b/include/linux/kho_radix_tree.h
@@ -11,15 +11,19 @@
/**
* DOC: Kexec Handover Radix Tree
*
- * This is a radix tree implementation for tracking physical memory pages
- * across kexec transitions. It was developed for the KHO mechanism but is
- * designed for broader use by any subsystem that needs to preserve pages.
+ * This is a radix tree implementation for tracking numeric keys across kexec
+ * transitions. It was developed for the KHO preserved memory map but is
+ * designed for broader use by any subsystem that needs to track keys.
+ * Conceptually speaking, the data structure is similar to a set. It tracks the
+ * presence or absence of numeric keys.
*
* The radix tree is a multi-level tree where leaf nodes are bitmaps
- * representing individual pages. To allow pages of different sizes (orders)
+ * representing individual keys.
+ *
+ * For the KHO preserved memory map, to allow pages of different sizes (orders)
* to be stored efficiently in a single tree, it uses a unique key encoding
- * scheme. Each key is an unsigned long that combines a page's physical
- * address and its order.
+ * scheme. Each key is an unsigned long that combines a page's physical address
+ * and its order.
*
* Client code is responsible for allocating the root node of the tree,
* initializing the mutex lock, and managing its lifecycle. It must use the
@@ -34,37 +38,53 @@ struct kho_radix_tree {
struct mutex lock; /* protects the tree's structure and root pointer */
};
-typedef int (*kho_radix_tree_walk_callback_t)(phys_addr_t phys,
- unsigned int order);
+/**
+ * struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
+ * @leaf: Called on each present key in the radix tree.
+ * @node: Called on each node of the radix tree itself. Receives the
+ * physical address of the page containing the node.
+ *
+ * For each callback, a return value of 0 continues the walk and a non-zero
+ * return value is directly returned to the caller.
+ */
+struct kho_radix_walk_cb {
+ int (*leaf)(unsigned long key, void *data);
+ int (*node)(phys_addr_t phys, void *data);
+};
#ifdef CONFIG_KEXEC_HANDOVER
-int kho_radix_add_page(struct kho_radix_tree *tree, unsigned long pfn,
- unsigned int order);
-
-void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn,
- unsigned int order);
-
+int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key);
+void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key);
int kho_radix_walk_tree(struct kho_radix_tree *tree,
- kho_radix_tree_walk_callback_t cb);
+ const struct kho_radix_walk_cb *cb, void *data);
+int kho_radix_init_tree(struct kho_radix_tree *tree, struct kho_radix_node *root);
+void kho_radix_destroy_tree(struct kho_radix_tree *tree);
#else /* #ifdef CONFIG_KEXEC_HANDOVER */
-static inline int kho_radix_add_page(struct kho_radix_tree *tree, long pfn,
- unsigned int order)
+static inline int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
{
return -EOPNOTSUPP;
}
-static inline void kho_radix_del_page(struct kho_radix_tree *tree,
- unsigned long pfn, unsigned int order) { }
+static inline void kho_radix_del_key(struct kho_radix_tree *tree,
+ unsigned long key) { }
static inline int kho_radix_walk_tree(struct kho_radix_tree *tree,
- kho_radix_tree_walk_callback_t cb)
+ const struct kho_radix_walk_cb *cb, void *data)
{
return -EOPNOTSUPP;
}
+static inline int kho_radix_init_tree(struct kho_radix_tree *tree,
+ struct kho_radix_node *root)
+{
+ return 0;
+}
+
+static inline void kho_radix_destroy_tree(struct kho_radix_tree *tree) { }
+
#endif /* #ifdef CONFIG_KEXEC_HANDOVER */
#endif /* _LINUX_KHO_RADIX_TREE_H */
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 63ea5417de84..6051abc0612c 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -25,6 +25,7 @@ struct file;
/**
* struct liveupdate_file_op_args - Arguments for file operation callbacks.
* @handler: The file handler being called.
+ * @session: The session this file belongs to.
* @retrieve_status: The retrieve status for the 'can_finish / finish'
* operation. A value of 0 means the retrieve has not been
* attempted, a positive value means the retrieve was
@@ -45,6 +46,7 @@ struct file;
*/
struct liveupdate_file_op_args {
struct liveupdate_file_handler *handler;
+ struct liveupdate_session *session;
int retrieve_status;
struct file *file;
u64 serialized_data;
@@ -247,6 +249,14 @@ void liveupdate_flb_put_incoming(struct liveupdate_flb *flb);
int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb);
+/* kernel can internally retrieve files */
+int liveupdate_get_file_incoming(struct liveupdate_session *s, u64 token,
+ struct file **filep);
+
+/* Get a token for an outgoing file, or -ENOENT if file is not preserved */
+int liveupdate_get_token_outgoing(struct liveupdate_session *s,
+ struct file *file, u64 *tokenp);
+
#else /* CONFIG_LIVEUPDATE */
static inline bool liveupdate_enabled(void)
@@ -299,5 +309,17 @@ static inline void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb)
{
}
+static inline int liveupdate_get_file_incoming(struct liveupdate_session *s,
+ u64 token, struct file **filep)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int liveupdate_get_token_outgoing(struct liveupdate_session *s,
+ struct file *file, u64 *tokenp)
+{
+ return -EOPNOTSUPP;
+}
+
#endif /* CONFIG_LIVEUPDATE */
#endif /* _LINUX_LIVEUPDATE_H */
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 5afcd99aa8c1..d62db9e776cf 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -51,6 +51,7 @@ extern unsigned long long max_possible_pfn;
* memory reservations yet, so we get scratch memory from the previous
* kernel that we know is good to use. It is the only memory that
* allocations may happen from in this phase.
+ * @MEMBLOCK_RSRV_HUGETLB: memory is reserved for hugetlb pages
*/
enum memblock_flags {
MEMBLOCK_NONE = 0x0, /* No special request */
@@ -61,6 +62,7 @@ enum memblock_flags {
MEMBLOCK_RSRV_NOINIT = 0x10, /* don't initialize struct pages */
MEMBLOCK_RSRV_KERN = 0x20, /* memory reserved for kernel use */
MEMBLOCK_KHO_SCRATCH = 0x40, /* scratch memory for kexec handover */
+ MEMBLOCK_RSRV_HUGETLB = 0x80, /* memory reserved for hugetlb pages */
};
/**
@@ -420,6 +422,7 @@ void *memblock_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align,
void *memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr, phys_addr_t max_addr,
int nid);
+void *memblock_alloc_hugetlb(phys_addr_t size, int nid, bool exact_nid);
static __always_inline void *memblock_alloc(phys_addr_t size, phys_addr_t align)
{
@@ -484,6 +487,7 @@ static inline __init_memblock bool memblock_bottom_up(void)
phys_addr_t memblock_phys_mem_size(void);
phys_addr_t memblock_reserved_size(void);
phys_addr_t memblock_reserved_kern_size(phys_addr_t limit, int nid);
+phys_addr_t memblock_reserved_hugetlb_size(phys_addr_t limit, int nid);
unsigned long memblock_estimated_nr_free_pages(void);
phys_addr_t memblock_start_of_DRAM(void);
phys_addr_t memblock_end_of_DRAM(void);
@@ -613,28 +617,9 @@ static inline void memtest_report_meminfo(struct seq_file *m) { }
#ifdef CONFIG_MEMBLOCK_KHO_SCRATCH
void memblock_set_kho_scratch_only(void);
void memblock_clear_kho_scratch_only(void);
-bool memblock_is_kho_scratch_memory(phys_addr_t addr);
-
-static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
- enum migratetype mt)
-{
- if (memblock_is_kho_scratch_memory(PFN_PHYS(pfn)))
- return MIGRATE_CMA;
- return mt;
-}
#else
static inline void memblock_set_kho_scratch_only(void) { }
static inline void memblock_clear_kho_scratch_only(void) { }
-static inline bool memblock_is_kho_scratch_memory(phys_addr_t addr)
-{
- return false;
-}
-
-static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
- enum migratetype mt)
-{
- return mt;
-}
#endif
#endif /* _LINUX_MEMBLOCK_H */