Skip to contentSkip to conversation

kho: make boot time huge page allocation work nicely with KHO

PATCH Superseded Pratyush Yadav 4 participants 60 messages Apr 29 – Jun 2

Subsystems (5)

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Pratyush Yadav

author maintainer
#0 lore raw

cover kho: make boot time huge page allocation work nicely with KHO

From: "Pratyush Yadav (Google)" <[email protected]>

Hi,

Gigantic huge page allocation is somewhat broken currently with KHO.

First, they break scratch size accounting. Since they are allocated using the memblock alloc APIs, they count towards RSRV_KERN, and this scratch size when using scratch_scale. This means if huge pages take a large enough chunk of system memory scratch size will blow up and fail to allocate.

Second, scratch can not contain preserved memory, and if hugepages are allocated from scratch, they will fail to be preserved with the upcoming hugetlb preservation series [0].

Fix this by introducing the concept of extended scratch areas. They are areas that the kernel discovers on boot by walking the radix tree and finding free memory ranges. See patch 10 for more details.

Discovering the scratch areas needs some changes to the radix tree APIs and to memblock. Patches 1-8 do that.

Patch 9 introduces extended scratch to memblock.

Patch 10 adds the extended scratch discovery logic.

Patch 11 cleans up the preserved memory map API.

Finally, patch 12 puts all the pieces together and uses only extended scratch for hugepage allocation and does not count then towards RSRV_KERN.

[0] https://lore.kernel.org/linux-mm/[email protected]/T/#u

Regards,
Pratyush Yadav

Pratyush Yadav (Google) (12):
kho: generalize radix tree APIs
kho: store incoming radix tree in kho_in
kho: add a struct for radix callbacks
kho: add callback for table pages
kho: add data argument to radix walk callback
kho: allow early-boot usage of the KHO radix tree
kho: allow destroying KHO radix tree
kho: add kho_radix_init_tree()
memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT
kho: extended scratch
kho: return virtual address of mem_map mm/hugetlb: make bootmem allocation work with KHO

 include/linux/kexec_handover.h     |   1 +
 include/linux/kho_radix_tree.h     |  44 ++--
 include/linux/memblock.h           |  14 ++
 kernel/liveupdate/kexec_handover.c | 389 ++++++++++++++++++++++-------
 mm/hugetlb.c                       |  19 +-
 mm/memblock.c                      | 177 ++++++++++---
 mm/mm_init.c                       |   1 +
 7 files changed, 489 insertions(+), 156 deletions(-)

base-commit: eee13213401bafb7ffe3b447adffb1f570b9d813

Signature · 1 line
2.54.0.545.g6539524ca2-goog
author maintainer
#1 lore raw

PATCH 1/12 kho: generalize radix tree APIs

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

Despite that, the radix tree APIs are very closely tied to KHO memory preservation tracking. Adding a key is done by kho_radix_add_page(), which encodes it as a page tracking operation and takes in PFN and order. kho_radix_del_page() does the same. These functions encode the key internally that goes into the radix tree. kho_radix_walk_tree() does the same by baking the PFN and order into the callback arguments.

Generalize the APIs by taking the key directly and doing the encoding at the callers. Rename the functions to kho_radix_add_key() and kho_radix_del_key(). In practice, this removes a line each from the functions and moves the encoding function call to the callers. Similarly, update kho_radix_tree_walk_callback_t to take the key directly.

To keep the naming convention clearer, rename kho_radix_{encode,decode}_key() to kho_{encode,decode}_radix_key().

---
 include/linux/kho_radix_tree.h     | 18 +++----
 kernel/liveupdate/kexec_handover.c | 76 ++++++++++++++----------------
 2 files changed, 42 insertions(+), 52 deletions(-)
include/linux/kho_radix_tree.h +6 -12
index 84e918b96e53..f368f3b9f923 100644
@@ -34,30 +34,24 @@ 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);
+typedef int (*kho_radix_tree_walk_callback_t)(unsigned long key);
 
 #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);
 
 #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)
kernel/liveupdate/kexec_handover.c +36 -40

190 lines not on this page · raw message

Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer Reviewed-by on v1 1/12
#2 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

Quoted 21 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

Despite that, the radix tree APIs are very closely tied to KHO memory preservation tracking. Adding a key is done by kho_radix_add_page(), which encodes it as a page tracking operation and takes in PFN and order. kho_radix_del_page() does the same. These functions encode the key internally that goes into the radix tree. kho_radix_walk_tree() does the same by baking the PFN and order into the callback arguments.

Generalize the APIs by taking the key directly and doing the encoding at the callers. Rename the functions to kho_radix_add_key() and kho_radix_del_key(). In practice, this removes a line each from the functions and moves the encoding function call to the callers. Similarly, update kho_radix_tree_walk_callback_t to take the key directly.

Quoted 4 lines

To keep the naming convention clearer, rename kho_radix_{encode,decode}_key() to kho_{encode,decode}_radix_key().

Quoted 255 lines
---
 include/linux/kho_radix_tree.h     | 18 +++----
 kernel/liveupdate/kexec_handover.c | 76 ++++++++++++++----------------
 2 files changed, 42 insertions(+), 52 deletions(-)
include/linux/kho_radix_tree.h +6 -12
index 84e918b96e53..f368f3b9f923 100644
@@ -34,30 +34,24 @@ 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);
+typedef int (*kho_radix_tree_walk_callback_t)(unsigned long key);
 
 #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);
 
 #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)
kernel/liveupdate/kexec_handover.c +36 -40
index 33fcf848ef95..ba568d34c5b4 100644
@@ -85,7 +85,7 @@ static struct kho_out kho_out = {
 };
 
 /**
- * kho_radix_encode_key - Encodes a physical address and order into a radix key.
+ * kho_encode_radix_key - Encodes a physical address and order into a radix key.
  * @phys: The physical address of the page.
  * @order: The order of the page.
  *
@@ -95,7 +95,7 @@ static struct kho_out kho_out = {
  *
  * Return: The encoded unsigned long radix key.
  */
-static unsigned long kho_radix_encode_key(phys_addr_t phys, unsigned int order)
+static unsigned long kho_encode_radix_key(phys_addr_t phys, unsigned int order)
 {
 	/* Order bits part */
 	unsigned long h = 1UL << (KHO_ORDER_0_LOG2 - order);
@@ -106,17 +106,17 @@ static unsigned long kho_radix_encode_key(phys_addr_t phys, unsigned int order)
 }
 
 /**
- * kho_radix_decode_key - Decodes a radix key back into a physical address and order.
+ * kho_decode_radix_key - Decodes a radix key back into a physical address and order.
  * @key: The unsigned long key to decode.
  * @order: An output parameter, a pointer to an unsigned int where the decoded
  *         page order will be stored.
  *
- * This function reverses the encoding performed by kho_radix_encode_key(),
+ * This function reverses the encoding performed by kho_encode_radix_key(),
  * extracting the original physical address and page order from a given key.
  *
  * Return: The decoded physical address.
  */
-static phys_addr_t kho_radix_decode_key(unsigned long key, unsigned int *order)
+static phys_addr_t kho_decode_radix_key(unsigned long key, unsigned int *order)
 {
 	unsigned int order_bit = fls64(key);
 	phys_addr_t phys;
@@ -144,24 +144,21 @@ static unsigned long kho_radix_get_table_index(unsigned long key,
 }
 
 /**
- * kho_radix_add_page - Marks a page as preserved in the radix tree.
+ * kho_radix_add_key - Add a key to the radix tree.
  * @tree: The KHO radix tree.
- * @pfn: The page frame number of the page to preserve.
- * @order: The order of the page.
+ * @key: The key to add.
  *
- * This function traverses the radix tree based on the key derived from @pfn
- * and @order. It sets the corresponding bit in the leaf bitmap to mark the
- * page for preservation. If intermediate nodes do not exist along the path,
- * they are allocated and added to the tree.
+ * This function traverses the radix tree based on the key provided. It sets the
+ * corresponding bit in the leaf bitmap to mark the key as present. If
+ * intermediate nodes do not exist along the path, they are allocated and added
+ * to the tree.
  *
  * Return: 0 on success, or a negative error code on failure.
  */
-int kho_radix_add_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)
 {
 	/* Newly allocated nodes for error cleanup */
 	struct kho_radix_node *intermediate_nodes[KHO_TREE_MAX_DEPTH] = { 0 };
-	unsigned long key = kho_radix_encode_key(PFN_PHYS(pfn), order);
 	struct kho_radix_node *anchor_node = NULL;
 	struct kho_radix_node *node = tree->root;
 	struct kho_radix_node *new_node;
@@ -224,22 +221,19 @@ int kho_radix_add_page(struct kho_radix_tree *tree,
 
 	return err;
 }
-EXPORT_SYMBOL_GPL(kho_radix_add_page);
+EXPORT_SYMBOL_GPL(kho_radix_add_key);
 
 /**
- * kho_radix_del_page - Removes a page's preservation status from the radix tree.
+ * kho_radix_del_key - Removes the key from the radix tree.
  * @tree: The KHO radix tree.
- * @pfn: The page frame number of the page to unpreserve.
- * @order: The order of the page.
+ * @key: The key to remove.
  *
  * This function traverses the radix tree and clears the bit corresponding to
- * the page, effectively removing its "preserved" status. It does not free
- * the tree's intermediate nodes, even if they become empty.
+ * the key, effectively removing it from the tree. It does not free the tree's
+ * intermediate nodes, even if they become empty.
  */
-void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn,
-			unsigned int order)
+void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 {
-	unsigned long key = kho_radix_encode_key(PFN_PHYS(pfn), order);
 	struct kho_radix_node *node = tree->root;
 	struct kho_radix_leaf *leaf;
 	unsigned int i, idx;
@@ -270,21 +264,18 @@ void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn,
 	idx = kho_radix_get_bitmap_index(key);
 	__clear_bit(idx, leaf->bitmap);
 }
-EXPORT_SYMBOL_GPL(kho_radix_del_page);
+EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
 static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
 			       unsigned long key,
 			       kho_radix_tree_walk_callback_t cb)
 {
 	unsigned long *bitmap = (unsigned long *)leaf;
-	unsigned int order;
-	phys_addr_t phys;
 	unsigned int i;
 	int err;
 
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		phys = kho_radix_decode_key(key | i, &order);
-		err = cb(phys, order);
+		err = cb(key | i);
 		if (err)
 			return err;
 	}
@@ -332,15 +323,14 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 }
 
 /**
- * kho_radix_walk_tree - Traverses the radix tree and calls a callback for each preserved page.
+ * kho_radix_walk_tree - Traverses the radix tree and calls a callback for each key.
  * @tree: A pointer to the KHO radix tree to walk.
  * @cb: A callback function of type kho_radix_tree_walk_callback_t that will be
- *      invoked for each preserved page found in the tree. The callback receives
- *      the physical address and order of the preserved page.
+ *      invoked for each key in the tree.
  *
  * This function walks the radix tree, searching from the specified top level
- * down to the lowest level (level 0). For each preserved page found, it invokes
- * the provided callback, passing the page's physical address and order.
+ * down to the lowest level (level 0). For each key found, it invokes the
+ * provided callback.
  *
  * Return: 0 if the walk completed the specified tree, or the non-zero return
  *         value from the callback that stopped the walk.
@@ -365,7 +355,8 @@ static void __kho_unpreserve(struct kho_radix_tree *tree,
 	while (pfn < end_pfn) {
 		order = min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));
 
-		kho_radix_del_page(tree, pfn, order);
+		kho_radix_del_key(tree, kho_encode_radix_key(PFN_PHYS(pfn),
+							     order));
 
 		pfn += 1 << order;
 	}
@@ -498,13 +489,16 @@ static struct page *__init kho_get_preserved_page(phys_addr_t phys,
 	return pfn_to_page(pfn);
 }
 
-static int __init kho_preserved_memory_reserve(phys_addr_t phys,
-					       unsigned int order)
+static int __init kho_preserved_memory_reserve(unsigned long key)
 {
 	union kho_page_info info;
 	struct page *page;
+	unsigned int order;
+	phys_addr_t phys;
 	u64 sz;
 
+	phys = kho_decode_radix_key(key, &order);
+
 	sz = 1 << (order + PAGE_SHIFT);
 	page = kho_get_preserved_page(phys, order);
 
@@ -858,7 +852,8 @@ int kho_preserve_folio(struct folio *folio)
 	if (WARN_ON(kho_scratch_overlap(pfn << PAGE_SHIFT, PAGE_SIZE << order)))
 		return -EINVAL;
 
-	return kho_radix_add_page(tree, pfn, order);
+	return kho_radix_add_key(tree, kho_encode_radix_key(PFN_PHYS(pfn),
+							    order));
 }
 EXPORT_SYMBOL_GPL(kho_preserve_folio);
 
@@ -876,7 +871,7 @@ void kho_unpreserve_folio(struct folio *folio)
 	const unsigned long pfn = folio_pfn(folio);
 	const unsigned int order = folio_order(folio);
 
-	kho_radix_del_page(tree, pfn, order);
+	kho_radix_del_key(tree, kho_encode_radix_key(PFN_PHYS(pfn), order));
 }
 EXPORT_SYMBOL_GPL(kho_unpreserve_folio);
 
@@ -916,7 +911,8 @@ int kho_preserve_pages(struct page *page, unsigned long nr_pages)
 		while (pfn_to_nid(pfn) != pfn_to_nid(pfn + (1UL << order) - 1))
 			order--;
 
-		err = kho_radix_add_page(tree, pfn, order);
+		err = kho_radix_add_key(tree, kho_encode_radix_key(PFN_PHYS(pfn),
+								   order));
 		if (err) {
 			failed_pfn = pfn;
 			break;
Signature · 1 line
2.54.0.545.g6539524ca2-goog
#3 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

In reply to Pratyush Yadav
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

"Arbitrary key": Not quite the complete 64-bits, rather 64 - PAGE_SIZE, correct?

Quoted 8 lines

+ * kho_radix_add_key - Add a key to the radix tree.
* @tree: The KHO radix tree.
+ * @key: The key to add.
*
+ * This function traverses the radix tree based on the key provided. It sets the
+ * corresponding bit in the leaf bitmap to mark the key as present. If
+ * intermediate nodes do not exist along the path, they are allocated and added
+ * to the tree.

Consider adding a note on the key-width limitation.

Best,
Jork

author maintainer
#4 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

Quoted 10 lines · Jork Loeser
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

"Arbitrary key": Not quite the complete 64-bits, rather 64 - PAGE_SIZE, correct?

Right, 64 - PAGE_SHIFT.

Quoted 11 lines
Quoted 9 lines

+ * kho_radix_add_key - Add a key to the radix tree.
* @tree: The KHO radix tree.
+ * @key: The key to add.
*
+ * This function traverses the radix tree based on the key provided. It sets the
+ * corresponding bit in the leaf bitmap to mark the key as present. If
+ * intermediate nodes do not exist along the path, they are allocated and added
+ * to the tree.

Consider adding a note on the key-width limitation.

I think adding a runtime check would also be a good idea here.

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#5 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

Quoted 22 lines · Pratyush Yadav
Quoted 10 lines · Jork Loeser
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

"Arbitrary key": Not quite the complete 64-bits, rather 64 - PAGE_SIZE,

correct?

Right, 64 - PAGE_SHIFT.

Quoted 6 lines
Quoted 6 lines

+ * kho_radix_add_key - Add a key to the radix tree.
* @tree: The KHO radix tree.
+ * @key: The key to add.
*
+ * This function traverses the radix tree based on the key provided.

Quoted 8 lines

It sets the

Quoted 2 lines
Quoted 2 lines

+ * corresponding bit in the leaf bitmap to mark the key as present. If
+ * intermediate nodes do not exist along the path, they are allocated

and added

Quoted 3 lines
Quoted 1 line

+ * to the tree.

Consider adding a note on the key-width limitation.

As a side effect, it should make sashiko happy.

Quoted 2 lines

I think adding a runtime check would also be a good idea here.

+1

Quoted 4 lines

--
Regards,
Pratyush Yadav

maintainer
#6 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

In reply to Pratyush Yadav
Quoted 35 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

Despite that, the radix tree APIs are very closely tied to KHO memory preservation tracking. Adding a key is done by kho_radix_add_page(), which encodes it as a page tracking operation and takes in PFN and order. kho_radix_del_page() does the same. These functions encode the key internally that goes into the radix tree. kho_radix_walk_tree() does the same by baking the PFN and order into the callback arguments.

Generalize the APIs by taking the key directly and doing the encoding at the callers. Rename the functions to kho_radix_add_key() and kho_radix_del_key(). In practice, this removes a line each from the functions and moves the encoding function call to the callers. Similarly, update kho_radix_tree_walk_callback_t to take the key directly.

To keep the naming convention clearer, rename kho_radix_{encode,decode}_key() to kho_{encode,decode}_radix_key().

---
 include/linux/kho_radix_tree.h     | 18 +++----
 kernel/liveupdate/kexec_handover.c | 76 ++++++++++++++----------------
 2 files changed, 42 insertions(+), 52 deletions(-)
include/linux/kho_radix_tree.h +0 -0
index 84e918b96e53..f368f3b9f923 100644

include/linux/kho_radix_tree.h static struct kho_out kho_out = { · line 88

Quoted 5 lines
include/linux/kho_radix_tree.h +1 -1
@@ -85,7 +85,7 @@ static struct kho_out kho_out = {
 };
 
 /**
- * kho_radix_encode_key - Encodes a physical address and order into a radix key.
+ * kho_encode_radix_key - Encodes a physical address and order into a radix key.

Let's keep kho_radix_ prefix for namespasing please. This is the common practice these days.

Quoted 3 lines
include/linux/kho_radix_tree.h +0 -0
  * @phys: The physical address of the page.
  * @order: The order of the page.
  *

...

Quoted 6 lines
include/linux/kho_radix_tree.h +1 -1
@@ -144,24 +144,21 @@ static unsigned long kho_radix_get_table_index(unsigned long key,
 }
 
 /**
- * kho_radix_add_page - Marks a page as preserved in the radix tree.
+ * kho_radix_add_key - Add a key to the radix tree.

include/linux/kho_radix_tree.h static unsigned long kho_radix_get_table_index(unsigned long key, · line 151

Quoted 10 lines
include/linux/kho_radix_tree.h +2 -6
  * @tree: The KHO radix tree.
- * @pfn: The page frame number of the page to preserve.
- * @order: The order of the page.
+ * @key: The key to add.
  *
- * This function traverses the radix tree based on the key derived from @pfn
- * and @order. It sets the corresponding bit in the leaf bitmap to mark the
- * page for preservation. If intermediate nodes do not exist along the path,
- * they are allocated and added to the tree.
+ * This function traverses the radix tree based on the key provided. It sets the

Nit: @key here and in
the comments below.

Quoted 6 lines
include/linux/kho_radix_tree.h +3 -0
+ * corresponding bit in the leaf bitmap to mark the key as present. If
+ * intermediate nodes do not exist along the path, they are allocated and added
+ * to the tree.
  *
  * Return: 0 on success, or a negative error code on failure.
  */
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#7 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

Quoted 38 lines · Mike Rapoport
Quoted 37 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

Despite that, the radix tree APIs are very closely tied to KHO memory preservation tracking. Adding a key is done by kho_radix_add_page(), which encodes it as a page tracking operation and takes in PFN and order. kho_radix_del_page() does the same. These functions encode the key internally that goes into the radix tree. kho_radix_walk_tree() does the same by baking the PFN and order into the callback arguments.

Generalize the APIs by taking the key directly and doing the encoding at the callers. Rename the functions to kho_radix_add_key() and kho_radix_del_key(). In practice, this removes a line each from the functions and moves the encoding function call to the callers. Similarly, update kho_radix_tree_walk_callback_t to take the key directly.

To keep the naming convention clearer, rename kho_radix_{encode,decode}_key() to kho_{encode,decode}_radix_key().

---
 include/linux/kho_radix_tree.h     | 18 +++----
 kernel/liveupdate/kexec_handover.c | 76 ++++++++++++++----------------
 2 files changed, 42 insertions(+), 52 deletions(-)
include/linux/kho_radix_tree.h +0 -0
index 84e918b96e53..f368f3b9f923 100644
@@ -85,7 +85,7 @@ static struct kho_out kho_out = {
 };
 
Quoted 6 lines

include/linux/kho_radix_tree.h static struct kho_out kho_out = { · line 88

Quoted 3 lines
include/linux/kho_radix_tree.h +1 -1
 /**
- * kho_radix_encode_key - Encodes a physical address and order into a radix key.
+ * kho_encode_radix_key - Encodes a physical address and order into a radix key.

Let's keep kho_radix_ prefix for namespasing please. This is the common practice these days.

I am keeping the namespacing, just moving it out of the "kho_radix" namespace to "kho" namespace. The mental model is that this function has nothing to do with the radix tree. It is just something KHO uses for one of its radix tree, so it should live in the "kho" namespace not "kho_radix".

Does that make sense? I can add this explanation to the commit message as well.

Quoted 10 lines
Quoted 4 lines
include/linux/kho_radix_tree.h +0 -0
  * @phys: The physical address of the page.
  * @order: The order of the page.
  *

...

Quoted 3 lines
include/linux/kho_radix_tree.h +0 -0
@@ -144,24 +144,21 @@ static unsigned long kho_radix_get_table_index(unsigned long key,
 }
 
Quoted 16 lines

include/linux/kho_radix_tree.h static unsigned long kho_radix_get_table_index(unsigned long key, · line 151

Quoted 13 lines
include/linux/kho_radix_tree.h +3 -7
 /**
- * kho_radix_add_page - Marks a page as preserved in the radix tree.
+ * kho_radix_add_key - Add a key to the radix tree.
  * @tree: The KHO radix tree.
- * @pfn: The page frame number of the page to preserve.
- * @order: The order of the page.
+ * @key: The key to add.
  *
- * This function traverses the radix tree based on the key derived from @pfn
- * and @order. It sets the corresponding bit in the leaf bitmap to mark the
- * page for preservation. If intermediate nodes do not exist along the path,
- * they are allocated and added to the tree.
+ * This function traverses the radix tree based on the key provided. It sets the

Nit: @key here and in
the comments below.

ACK.

Quoted 7 lines
Quoted 7 lines
include/linux/kho_radix_tree.h +3 -0
+ * corresponding bit in the leaf bitmap to mark the key as present. If
+ * intermediate nodes do not exist along the path, they are allocated and added
+ * to the tree.
  *
  * Return: 0 on success, or a negative error code on failure.
  */
Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#8 lore raw

Re: [PATCH 01/12] kho: generalize radix tree APIs

Quoted 47 lines · Pratyush Yadav
Quoted 38 lines · Mike Rapoport
Quoted 37 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree is a data structure that can track the presence or absence of an arbitrary key, with nothing inherently tied to KHO memory preservation tracking. This was one of the design goals of the radix tree. This was done to enable it to be re-used by other users of KHO.

Despite that, the radix tree APIs are very closely tied to KHO memory preservation tracking. Adding a key is done by kho_radix_add_page(), which encodes it as a page tracking operation and takes in PFN and order. kho_radix_del_page() does the same. These functions encode the key internally that goes into the radix tree. kho_radix_walk_tree() does the same by baking the PFN and order into the callback arguments.

Generalize the APIs by taking the key directly and doing the encoding at the callers. Rename the functions to kho_radix_add_key() and kho_radix_del_key(). In practice, this removes a line each from the functions and moves the encoding function call to the callers. Similarly, update kho_radix_tree_walk_callback_t to take the key directly.

To keep the naming convention clearer, rename kho_radix_{encode,decode}_key() to kho_{encode,decode}_radix_key().

---
 include/linux/kho_radix_tree.h     | 18 +++----
 kernel/liveupdate/kexec_handover.c | 76 ++++++++++++++----------------
 2 files changed, 42 insertions(+), 52 deletions(-)
include/linux/kho_radix_tree.h +0 -0
index 84e918b96e53..f368f3b9f923 100644
@@ -85,7 +85,7 @@ static struct kho_out kho_out = {
 };
 
Quoted 6 lines

include/linux/kho_radix_tree.h static struct kho_out kho_out = { · line 88

Quoted 3 lines
include/linux/kho_radix_tree.h +1 -1
 /**
- * kho_radix_encode_key - Encodes a physical address and order into a radix key.
+ * kho_encode_radix_key - Encodes a physical address and order into a radix key.

Let's keep kho_radix_ prefix for namespasing please. This is the common practice these days.

Quoted 8 lines

I am keeping the namespacing, just moving it out of the "kho_radix" namespace to "kho" namespace. The mental model is that this function has nothing to do with the radix tree. It is just something KHO uses for one of its radix tree, so it should live in the "kho" namespace not "kho_radix".

Does that make sense? I can add this explanation to the commit message as well.

With this explanation it makes sense, with "to keep the naming convention clearer" it felt the opposite :)

Quoted 3 lines
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#9 lore raw

PATCH 2/12 kho: store incoming radix tree in kho_in

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

This allows other functions to also use the radix tree. While at it, also use kho_get_mem_map_phys() instead of duplicating the code to get the radix tree root from the FDT.

---
 kernel/liveupdate/kexec_handover.c | 27 ++++++++-------------------
 1 file changed, 8 insertions(+), 19 deletions(-)
kernel/liveupdate/kexec_handover.c +8 -19
index ba568d34c5b4..5758dc6fab5d 100644
@@ -1294,6 +1294,7 @@ struct kho_in {
 	char previous_release[__NEW_UTS_LEN + 1];
 	u32 kexec_count;
 	struct kho_debugfs dbg;
+	struct kho_radix_tree radix_tree;
 };
 
 static struct kho_in kho_in = {
@@ -1373,24 +1374,10 @@ EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
 static int __init kho_mem_retrieve(const void *fdt)
 {
-	struct kho_radix_tree tree;
-	const phys_addr_t *mem;
-	int len;
-
-	/* Retrieve the KHO radix tree from passed-in FDT. */
-	mem = fdt_getprop(fdt, 0, KHO_FDT_MEMORY_MAP_PROP_NAME, &len);
-
-	if (!mem || len != sizeof(*mem)) {
-		pr_err("failed to get preserved KHO memory tree\n");
-		return -ENOENT;
-	}
-
-	if (!*mem)
-		return -EINVAL;
-
-	tree.root = phys_to_virt(*mem);
-	mutex_init(&tree.lock);
-	return kho_radix_walk_tree(&tree, kho_preserved_memory_reserve);
+	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));
+	mutex_init(&kho_in.radix_tree.lock);
+	return kho_radix_walk_tree(&kho_in.radix_tree,
+				   kho_preserved_memory_reserve);
 }
 
 static __init int kho_out_fdt_setup(void)
@@ -1597,8 +1584,10 @@ void __init kho_memory_init(void)
 	if (kho_in.scratch_phys) {
 		kho_scratch = phys_to_virt(kho_in.scratch_phys);
 
-		if (kho_mem_retrieve(kho_get_fdt()))
+		if (kho_mem_retrieve(kho_get_fdt())) {
 			kho_in.fdt_phys = 0;
+			kho_in.radix_tree.root = NULL;
+		}
 	} else {
 		kho_reserve_scratch();
 	}
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#10 lore raw

Re: [PATCH 02/12] kho: store incoming radix tree in kho_in

Quoted 36 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

This allows other functions to also use the radix tree. While at it, also use kho_get_mem_map_phys() instead of duplicating the code to get the radix tree root from the FDT.

---
 kernel/liveupdate/kexec_handover.c | 27 ++++++++-------------------
 1 file changed, 8 insertions(+), 19 deletions(-)
kernel/liveupdate/kexec_handover.c +1 -9
index ba568d34c5b4..5758dc6fab5d 100644
@@ -1294,6 +1294,7 @@ struct kho_in {
 	char previous_release[__NEW_UTS_LEN + 1];
 	u32 kexec_count;
 	struct kho_debugfs dbg;
+	struct kho_radix_tree radix_tree;
 };
 
 static struct kho_in kho_in = {
@@ -1373,24 +1374,10 @@ EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
 static int __init kho_mem_retrieve(const void *fdt)
 {
-	struct kho_radix_tree tree;
-	const phys_addr_t *mem;
-	int len;
-
-	/* Retrieve the KHO radix tree from passed-in FDT. */
-	mem = fdt_getprop(fdt, 0, KHO_FDT_MEMORY_MAP_PROP_NAME, &len);
-
-	if (!mem || len != sizeof(*mem)) {
-		pr_err("failed to get preserved KHO memory tree\n");

kernel/liveupdate/kexec_handover.c EXPORT_SYMBOL_GPL(kho_retrieve_subtree); · line 1377

Quoted 10 lines
kernel/liveupdate/kexec_handover.c +1 -9
-		return -ENOENT;
-	}
-
-	if (!*mem)
-		return -EINVAL;
-
-	tree.root = phys_to_virt(*mem);
-	mutex_init(&tree.lock);
-	return kho_radix_walk_tree(&tree, kho_preserved_memory_reserve);
+	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));

Do we really want to remove an explicit check for 0 and get a WARN() in kho_radix_walk_tree()?

Quoted 7 lines
kernel/liveupdate/kexec_handover.c +3 -0
+	mutex_init(&kho_in.radix_tree.lock);
+	return kho_radix_walk_tree(&kho_in.radix_tree,
+				   kho_preserved_memory_reserve);
 }
 
 static __init int kho_out_fdt_setup(void)

kernel/liveupdate/kexec_handover.c void __init kho_memory_init(void) · line 1589

Quoted 7 lines
kernel/liveupdate/kexec_handover.c +2 -1
@@ -1597,8 +1584,10 @@ void __init kho_memory_init(void)
 	if (kho_in.scratch_phys) {
 		kho_scratch = phys_to_virt(kho_in.scratch_phys);
 
-		if (kho_mem_retrieve(kho_get_fdt()))
+		if (kho_mem_retrieve(kho_get_fdt())) {
 			kho_in.fdt_phys = 0;
+			kho_in.radix_tree.root = NULL;

I'd make kho_mem_retrieve() void and put these there.

Quoted 7 lines
kernel/liveupdate/kexec_handover.c +1 -0
+		}
 	} else {
 		kho_reserve_scratch();
 	}
Signature · 1 line
2.54.0.545.g6539524ca2-goog
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#11 lore raw

Re: [PATCH 02/12] kho: store incoming radix tree in kho_in

Quoted 42 lines · Mike Rapoport
Quoted 41 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

This allows other functions to also use the radix tree. While at it, also use kho_get_mem_map_phys() instead of duplicating the code to get the radix tree root from the FDT.

---
 kernel/liveupdate/kexec_handover.c | 27 ++++++++-------------------
 1 file changed, 8 insertions(+), 19 deletions(-)
kernel/liveupdate/kexec_handover.c +1 -14
index ba568d34c5b4..5758dc6fab5d 100644
@@ -1294,6 +1294,7 @@ struct kho_in {
 	char previous_release[__NEW_UTS_LEN + 1];
 	u32 kexec_count;
 	struct kho_debugfs dbg;
+	struct kho_radix_tree radix_tree;
 };
 
 static struct kho_in kho_in = {
@@ -1373,24 +1374,10 @@ EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
 static int __init kho_mem_retrieve(const void *fdt)
 {
-	struct kho_radix_tree tree;
-	const phys_addr_t *mem;
-	int len;
-
-	/* Retrieve the KHO radix tree from passed-in FDT. */
-	mem = fdt_getprop(fdt, 0, KHO_FDT_MEMORY_MAP_PROP_NAME, &len);
-
-	if (!mem || len != sizeof(*mem)) {
-		pr_err("failed to get preserved KHO memory tree\n");
-		return -ENOENT;
-	}
-
-	if (!*mem)
-		return -EINVAL;
Quoted 8 lines

kernel/liveupdate/kexec_handover.c EXPORT_SYMBOL_GPL(kho_retrieve_subtree); · line 1377

Quoted 5 lines
kernel/liveupdate/kexec_handover.c +1 -4
-
-	tree.root = phys_to_virt(*mem);
-	mutex_init(&tree.lock);
-	return kho_radix_walk_tree(&tree, kho_preserved_memory_reserve);
+	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));

Do we really want to remove an explicit check for 0 and get a WARN() in kho_radix_walk_tree()?

If mem_map_phys is 0 then kho_populate() never sets kho_in.scratch_phys and thus kho_mem_retrieve() never gets called. So here it will never be 0, and if it is, a WARN() is certainly warranted.

Perhaps I should add a comment since this isn't so obvious?

Quoted 11 lines
Quoted 11 lines
kernel/liveupdate/kexec_handover.c +3 -0
+	mutex_init(&kho_in.radix_tree.lock);
+	return kho_radix_walk_tree(&kho_in.radix_tree,
+				   kho_preserved_memory_reserve);
 }
 
 static __init int kho_out_fdt_setup(void)
@@ -1597,8 +1584,10 @@ void __init kho_memory_init(void)
 	if (kho_in.scratch_phys) {
 		kho_scratch = phys_to_virt(kho_in.scratch_phys);
 
Quoted 6 lines

kernel/liveupdate/kexec_handover.c void __init kho_memory_init(void) · line 1589

Quoted 4 lines
kernel/liveupdate/kexec_handover.c +2 -1
-		if (kho_mem_retrieve(kho_get_fdt()))
+		if (kho_mem_retrieve(kho_get_fdt())) {
 			kho_in.fdt_phys = 0;
+			kho_in.radix_tree.root = NULL;

I'd make kho_mem_retrieve() void and put these there.

Sure, will do.

Quoted 8 lines
Quoted 8 lines
kernel/liveupdate/kexec_handover.c +1 -0
+		}
 	} else {
 		kho_reserve_scratch();
 	}
Signature · 1 line
2.54.0.545.g6539524ca2-goog
Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#12 lore raw

Re: [PATCH 02/12] kho: store incoming radix tree in kho_in

Quoted 53 lines · Pratyush Yadav
Quoted 42 lines · Mike Rapoport
Quoted 41 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

This allows other functions to also use the radix tree. While at it, also use kho_get_mem_map_phys() instead of duplicating the code to get the radix tree root from the FDT.

---
 kernel/liveupdate/kexec_handover.c | 27 ++++++++-------------------
 1 file changed, 8 insertions(+), 19 deletions(-)
kernel/liveupdate/kexec_handover.c +1 -14
index ba568d34c5b4..5758dc6fab5d 100644
@@ -1294,6 +1294,7 @@ struct kho_in {
 	char previous_release[__NEW_UTS_LEN + 1];
 	u32 kexec_count;
 	struct kho_debugfs dbg;
+	struct kho_radix_tree radix_tree;
 };
 
 static struct kho_in kho_in = {
@@ -1373,24 +1374,10 @@ EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
 static int __init kho_mem_retrieve(const void *fdt)
 {
-	struct kho_radix_tree tree;
-	const phys_addr_t *mem;
-	int len;
-
-	/* Retrieve the KHO radix tree from passed-in FDT. */
-	mem = fdt_getprop(fdt, 0, KHO_FDT_MEMORY_MAP_PROP_NAME, &len);
-
-	if (!mem || len != sizeof(*mem)) {
-		pr_err("failed to get preserved KHO memory tree\n");
-		return -ENOENT;
-	}
-
-	if (!*mem)
-		return -EINVAL;
Quoted 8 lines

kernel/liveupdate/kexec_handover.c EXPORT_SYMBOL_GPL(kho_retrieve_subtree); · line 1377

Quoted 5 lines
kernel/liveupdate/kexec_handover.c +1 -4
-
-	tree.root = phys_to_virt(*mem);
-	mutex_init(&tree.lock);
-	return kho_radix_walk_tree(&tree, kho_preserved_memory_reserve);
+	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));

Do we really want to remove an explicit check for 0 and get a WARN() in kho_radix_walk_tree()?

Quoted 5 lines

If mem_map_phys is 0 then kho_populate() never sets kho_in.scratch_phys and thus kho_mem_retrieve() never gets called. So here it will never be 0, and if it is, a WARN() is certainly warranted.

Perhaps I should add a comment since this isn't so obvious?

Yes, please.
After a few weeks it will be completely obscure.

Quoted 32 lines
Quoted 11 lines
Quoted 11 lines
kernel/liveupdate/kexec_handover.c +3 -0
+	mutex_init(&kho_in.radix_tree.lock);
+	return kho_radix_walk_tree(&kho_in.radix_tree,
+				   kho_preserved_memory_reserve);
 }
 
 static __init int kho_out_fdt_setup(void)
@@ -1597,8 +1584,10 @@ void __init kho_memory_init(void)
 	if (kho_in.scratch_phys) {
 		kho_scratch = phys_to_virt(kho_in.scratch_phys);
 
Quoted 6 lines

kernel/liveupdate/kexec_handover.c void __init kho_memory_init(void) · line 1589

Quoted 4 lines
kernel/liveupdate/kexec_handover.c +2 -1
-		if (kho_mem_retrieve(kho_get_fdt()))
+		if (kho_mem_retrieve(kho_get_fdt())) {
 			kho_in.fdt_phys = 0;
+			kho_in.radix_tree.root = NULL;

I'd make kho_mem_retrieve() void and put these there.

Sure, will do.

Quoted 8 lines
Quoted 8 lines
kernel/liveupdate/kexec_handover.c +1 -0
+		}
 	} else {
 		kho_reserve_scratch();
 	}
Signature · 1 line
2.54.0.545.g6539524ca2-goog
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.
maintainer
#13 lore raw

Re: [PATCH 02/12] kho: store incoming radix tree in kho_in

In reply to Pratyush Yadav
Quoted 70 lines · Pratyush Yadav
Quoted 42 lines · Mike Rapoport
Quoted 41 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

This allows other functions to also use the radix tree. While at it, also use kho_get_mem_map_phys() instead of duplicating the code to get the radix tree root from the FDT.

---
 kernel/liveupdate/kexec_handover.c | 27 ++++++++-------------------
 1 file changed, 8 insertions(+), 19 deletions(-)
kernel/liveupdate/kexec_handover.c +1 -14
index ba568d34c5b4..5758dc6fab5d 100644
@@ -1294,6 +1294,7 @@ struct kho_in {
 	char previous_release[__NEW_UTS_LEN + 1];
 	u32 kexec_count;
 	struct kho_debugfs dbg;
+	struct kho_radix_tree radix_tree;
 };
 
 static struct kho_in kho_in = {
@@ -1373,24 +1374,10 @@ EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
 static int __init kho_mem_retrieve(const void *fdt)
 {
-	struct kho_radix_tree tree;
-	const phys_addr_t *mem;
-	int len;
-
-	/* Retrieve the KHO radix tree from passed-in FDT. */
-	mem = fdt_getprop(fdt, 0, KHO_FDT_MEMORY_MAP_PROP_NAME, &len);
-
-	if (!mem || len != sizeof(*mem)) {
-		pr_err("failed to get preserved KHO memory tree\n");
-		return -ENOENT;
-	}
-
-	if (!*mem)
-		return -EINVAL;
Quoted 8 lines

kernel/liveupdate/kexec_handover.c EXPORT_SYMBOL_GPL(kho_retrieve_subtree); · line 1377

Quoted 5 lines
kernel/liveupdate/kexec_handover.c +1 -4
-
-	tree.root = phys_to_virt(*mem);
-	mutex_init(&tree.lock);
-	return kho_radix_walk_tree(&tree, kho_preserved_memory_reserve);
+	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));

Do we really want to remove an explicit check for 0 and get a WARN() in kho_radix_walk_tree()?

If mem_map_phys is 0 then kho_populate() never sets kho_in.scratch_phys and thus kho_mem_retrieve() never gets called. So here it will never be 0, and if it is, a WARN() is certainly warranted.

Perhaps I should add a comment since this isn't so obvious?

Quoted 11 lines
Quoted 11 lines
kernel/liveupdate/kexec_handover.c +3 -0
+	mutex_init(&kho_in.radix_tree.lock);
+	return kho_radix_walk_tree(&kho_in.radix_tree,
+				   kho_preserved_memory_reserve);
 }
 
 static __init int kho_out_fdt_setup(void)
@@ -1597,8 +1584,10 @@ void __init kho_memory_init(void)
 	if (kho_in.scratch_phys) {
 		kho_scratch = phys_to_virt(kho_in.scratch_phys);
 
Quoted 8 lines
Quoted 6 lines

kernel/liveupdate/kexec_handover.c void __init kho_memory_init(void) · line 1589

Quoted 4 lines
kernel/liveupdate/kexec_handover.c +2 -1
-		if (kho_mem_retrieve(kho_get_fdt()))
+		if (kho_mem_retrieve(kho_get_fdt())) {
 			kho_in.fdt_phys = 0;
+			kho_in.radix_tree.root = NULL;

I'd make kho_mem_retrieve() void and put these there.

Sure, will do.

+1 on this one, otherwise LGTM.

Pasha

Quoted 13 lines
Quoted 9 lines
Quoted 9 lines
kernel/liveupdate/kexec_handover.c +1 -0
+		}
 	} else {
 		kho_reserve_scratch();
 	}
Signature · 1 line
2.54.0.545.g6539524ca2-goog
Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#14 lore raw

PATCH 3/12 kho: add a struct for radix callbacks

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

A future commit will add more callbacks for the KHO radix tree. Add a struct for collecting the callbacks.

---
 include/linux/kho_radix_tree.h     | 15 ++++++++++++---
 kernel/liveupdate/kexec_handover.c | 29 ++++++++++++++++-------------
 2 files changed, 28 insertions(+), 16 deletions(-)
include/linux/kho_radix_tree.h +12 -3
index f368f3b9f923..030da6399d28 100644
@@ -34,14 +34,23 @@ struct kho_radix_tree {
 	struct mutex lock; /* protects the tree's structure and root pointer */
 };
 
-typedef int (*kho_radix_tree_walk_callback_t)(unsigned long key);
+/**
+ * struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
+ * @key:      Called on each present key in the radix tree.
+ *
+ * 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 (*key)(unsigned long key);
+};
 
 #ifdef CONFIG_KEXEC_HANDOVER
 
 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);
 
 #else  /* #ifdef CONFIG_KEXEC_HANDOVER */
 
@@ -54,7 +63,7 @@ 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)
 {
 	return -EOPNOTSUPP;
 }
kernel/liveupdate/kexec_handover.c +16 -13
index 5758dc6fab5d..4a5d1b47799c 100644
@@ -266,16 +266,18 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
-static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
-			       unsigned long key,
-			       kho_radix_tree_walk_callback_t cb)
+static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
+			       const struct kho_radix_walk_cb *cb)
 {
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
+	if (!cb->key)
+		return 0;
+
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb(key | i);
+		err = cb->key(key | i);
 		if (err)
 			return err;
 	}
@@ -285,7 +287,7 @@ static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
 
 static int __kho_radix_walk_tree(struct kho_radix_node *root,
 				 unsigned int level, unsigned long start,
-				 kho_radix_tree_walk_callback_t cb)
+				 const struct kho_radix_walk_cb *cb)
 {
 	struct kho_radix_node *node;
 	struct kho_radix_leaf *leaf;
@@ -325,18 +327,16 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 /**
  * kho_radix_walk_tree - Traverses the radix tree and calls a callback for each key.
  * @tree: A pointer to the KHO radix tree to walk.
- * @cb: A callback function of type kho_radix_tree_walk_callback_t that will be
- *      invoked for each key in the tree.
+ * @cb:   Set of callbacks to be invoked during the tree walk.
  *
- * This function walks the radix tree, searching from the specified top level
- * down to the lowest level (level 0). For each key found, it invokes the
- * provided callback.
+ * This function walks the radix tree, searching from the top level down to the
+ * lowest level (level 0), invoking the appropriate callbacks.
  *
  * Return: 0 if the walk completed the specified tree, or the non-zero return
  *         value from the callback that stopped the walk.
  */
 int kho_radix_walk_tree(struct kho_radix_tree *tree,
-			kho_radix_tree_walk_callback_t cb)
+			const struct kho_radix_walk_cb *cb)
 {
 	if (WARN_ON_ONCE(!tree->root))
 		return -EINVAL;
@@ -1374,10 +1374,13 @@ EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
 
 static int __init kho_mem_retrieve(const void *fdt)
 {
+	const struct kho_radix_walk_cb cb = {
+		.key = kho_preserved_memory_reserve,
+	};
+
 	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));
 	mutex_init(&kho_in.radix_tree.lock);
-	return kho_radix_walk_tree(&kho_in.radix_tree,
-				   kho_preserved_memory_reserve);
+	return kho_radix_walk_tree(&kho_in.radix_tree, &cb);
 }
 
 static __init int kho_out_fdt_setup(void)
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#15 lore raw

Re: [PATCH 03/12] kho: add a struct for radix callbacks

Quoted 64 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

A future commit will add more callbacks for the KHO radix tree. Add a struct for collecting the callbacks.

---
 include/linux/kho_radix_tree.h     | 15 ++++++++++++---
 kernel/liveupdate/kexec_handover.c | 29 ++++++++++++++++-------------
 2 files changed, 28 insertions(+), 16 deletions(-)
include/linux/kho_radix_tree.h +12 -3
index f368f3b9f923..030da6399d28 100644
@@ -34,14 +34,23 @@ struct kho_radix_tree {
 	struct mutex lock; /* protects the tree's structure and root pointer */
 };
 
-typedef int (*kho_radix_tree_walk_callback_t)(unsigned long key);
+/**
+ * struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
+ * @key:      Called on each present key in the radix tree.
+ *
+ * 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 (*key)(unsigned long key);
+};
 
 #ifdef CONFIG_KEXEC_HANDOVER
 
 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);
 
 #else  /* #ifdef CONFIG_KEXEC_HANDOVER */
 
@@ -54,7 +63,7 @@ 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)
 {
 	return -EOPNOTSUPP;
 }
kernel/liveupdate/kexec_handover.c +2 -3
index 5758dc6fab5d..4a5d1b47799c 100644
@@ -266,16 +266,18 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
-static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
-			       unsigned long key,
-			       kho_radix_tree_walk_callback_t cb)
+static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
+			       const struct kho_radix_walk_cb *cb)
 {

kernel/liveupdate/kexec_handover.c void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key) · line 280

Quoted 10 lines
kernel/liveupdate/kexec_handover.c +4 -1
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
+	if (!cb->key)
+		return 0;
+
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb(key | i);
+		err = cb->key(key | i);

key(key) reads weird :)
Can't say I have a good name, maybe key_action()?

Quoted 3 lines
kernel/liveupdate/kexec_handover.c +0 -0
 		if (err)
 			return err;
 	}
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#16 lore raw

Re: [PATCH 03/12] kho: add a struct for radix callbacks

Quoted 8 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

A future commit will add more callbacks for the KHO radix tree. Add a struct for collecting the callbacks.

---

[...]

Quoted 16 lines
Quoted 16 lines
kernel/liveupdate/kexec_handover.c +2 -3
@@ -266,16 +266,18 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
-static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
-			       unsigned long key,
-			       kho_radix_tree_walk_callback_t cb)
+static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
+			       const struct kho_radix_walk_cb *cb)
 {
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
Quoted 9 lines

kernel/liveupdate/kexec_handover.c void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key) · line 280

Quoted 6 lines
kernel/liveupdate/kexec_handover.c +4 -1
+	if (!cb->key)
+		return 0;
+
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb(key | i);
+		err = cb->key(key | i);

key(key) reads weird :)
Can't say I have a good name, maybe key_action()?

I thought the context of it being under a callback struct would make it more obvious. I don't like key_action() much better TBH, but I don't have a strong opinion. Perhaps Pasha can suggest a 3rd option and we pick on randomly ;-)

Quoted 4 lines
Quoted 4 lines
kernel/liveupdate/kexec_handover.c +0 -0
 		if (err)
 			return err;
 	}
Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#17 lore raw

Re: [PATCH 03/12] kho: add a struct for radix callbacks

Quoted 37 lines · Pratyush Yadav
Quoted 8 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

A future commit will add more callbacks for the KHO radix tree. Add a struct for collecting the callbacks.

---

[...]

Quoted 16 lines
Quoted 16 lines
kernel/liveupdate/kexec_handover.c +2 -3
@@ -266,16 +266,18 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
-static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
-			       unsigned long key,
-			       kho_radix_tree_walk_callback_t cb)
+static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
+			       const struct kho_radix_walk_cb *cb)
 {
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
Quoted 9 lines

kernel/liveupdate/kexec_handover.c void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key) · line 280

Quoted 6 lines
kernel/liveupdate/kexec_handover.c +4 -1
+	if (!cb->key)
+		return 0;
+
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb(key | i);
+		err = cb->key(key | i);

key(key) reads weird :)
Can't say I have a good name, maybe key_action()?

Quoted 4 lines

I thought the context of it being under a callback struct would make it more obvious. I don't like key_action() much better TBH, but I don't have a strong opinion. Perhaps Pasha can suggest a 3rd option and we pick on randomly ;-)

Another option I thought is to call them ->leaf() and ->node().

Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
kernel/liveupdate/kexec_handover.c +0 -0
 		if (err)
 			return err;
 	}
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#18 lore raw

Re: [PATCH 03/12] kho: add a struct for radix callbacks

Quoted 38 lines · Mike Rapoport
Quoted 37 lines · Pratyush Yadav
Quoted 8 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

A future commit will add more callbacks for the KHO radix tree. Add a struct for collecting the callbacks.

---

[...]

Quoted 25 lines
Quoted 12 lines
kernel/liveupdate/kexec_handover.c +2 -3
@@ -266,16 +266,18 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
-static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
-			       unsigned long key,
-			       kho_radix_tree_walk_callback_t cb)
+static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
+			       const struct kho_radix_walk_cb *cb)
 {

kernel/liveupdate/kexec_handover.c void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key) · line 280

Quoted 10 lines
kernel/liveupdate/kexec_handover.c +4 -1
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
+	if (!cb->key)
+		return 0;
+
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb(key | i);
+		err = cb->key(key | i);

key(key) reads weird :)
Can't say I have a good name, maybe key_action()?

Quoted 6 lines
Quoted 4 lines

I thought the context of it being under a callback struct would make it more obvious. I don't like key_action() much better TBH, but I don't have a strong opinion. Perhaps Pasha can suggest a 3rd option and we pick on randomly ;-)

Another option I thought is to call them ->leaf() and ->node().

This one sounds nice. Will use it in v2.

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#19 lore raw

Re: [PATCH 03/12] kho: add a struct for radix callbacks

Quoted 40 lines · Pratyush Yadav
Quoted 38 lines · Mike Rapoport
Quoted 37 lines · Pratyush Yadav
Quoted 8 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

A future commit will add more callbacks for the KHO radix tree. Add a struct for collecting the callbacks.

---

[...]

Quoted 25 lines
Quoted 12 lines
kernel/liveupdate/kexec_handover.c +2 -3
@@ -266,16 +266,18 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
-static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf,
-			       unsigned long key,
-			       kho_radix_tree_walk_callback_t cb)
+static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
+			       const struct kho_radix_walk_cb *cb)
 {

kernel/liveupdate/kexec_handover.c void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key) · line 280

Quoted 10 lines
kernel/liveupdate/kexec_handover.c +4 -1
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
+	if (!cb->key)
+		return 0;
+
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb(key | i);
+		err = cb->key(key | i);

key(key) reads weird :)
Can't say I have a good name, maybe key_action()?

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

I thought the context of it being under a callback struct would make it more obvious. I don't like key_action() much better TBH, but I don't have a strong opinion. Perhaps Pasha can suggest a 3rd option and we pick on randomly ;-)

Another option I thought is to call them ->leaf() and ->node().

This one sounds nice. Will use it in v2.

Thank you. I also prefer ->leaf() and ->node(); they are simple and applicable to any tree.

Quoted 4 lines
Signature · 3 lines
-- 
Regards,
Pratyush Yadav
author maintainer
#20 lore raw

PATCH 4/12 kho: add callback for table pages

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO memory preservation radix tree does not mark the table pages themselves as scratch. This is done to avoid a circular dependency where preserving a page can lead of allocating other preserved pages. This means any walker looking for free ranges of memory outside of scratch areas will ignore the table

Add a table callback that is invoked for each table page. The callback is given the physical address of the table page.

---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 12 ++++++++++++
 2 files changed, 15 insertions(+)
include/linux/kho_radix_tree.h +3 -0
index 030da6399d28..fe7151d89361 100644
@@ -37,12 +37,15 @@ struct kho_radix_tree {
 /**
  * struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
  * @key:      Called on each present key in the radix tree.
+ * @table:    Called on each table of the radix tree itself. Receives the
+ *            physical address of the page containing the table.
  *
  * 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 (*key)(unsigned long key);
+	int (*table)(phys_addr_t phys);
 };
 
 #ifdef CONFIG_KEXEC_HANDOVER
kernel/liveupdate/kexec_handover.c +12 -0
index 4a5d1b47799c..94ca831b41c9 100644
@@ -273,6 +273,12 @@ static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 	unsigned int i;
 	int err;
 
+	if (cb->table) {
+		err = cb->table(virt_to_phys(leaf));
+		if (err)
+			return err;
+	}
+
 	if (!cb->key)
 		return 0;
 
@@ -295,6 +301,12 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 	unsigned int shift;
 	int err;
 
+	if (cb->table) {
+		err = cb->table(virt_to_phys(root));
+		if (err)
+			return err;
+	}
+
 	for (i = 0; i < PAGE_SIZE / sizeof(phys_addr_t); i++) {
 		if (!root->table[i])
 			continue;
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#21 lore raw

Re: [PATCH 04/12] kho: add callback for table pages

Quoted 9 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO memory preservation radix tree does not mark the table pages themselves as scratch. This is done to avoid a circular dependency where preserving a page can lead of allocating other preserved pages. This means any walker looking for free ranges of memory outside of scratch areas will ignore the table

Add a table callback that is invoked for each table page. The callback

A sentence why a table callback helps would be nice here :)

Quoted 15 lines

is given the physical address of the table page.

---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 12 ++++++++++++
 2 files changed, 15 insertions(+)
include/linux/kho_radix_tree.h +0 -0
index 030da6399d28..fe7151d89361 100644
@@ -37,12 +37,15 @@ struct kho_radix_tree {
 /**
  * struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.

include/linux/kho_radix_tree.h struct kho_radix_tree { · line 48

Quoted 10 lines
include/linux/kho_radix_tree.h +3 -0
  * @key:      Called on each present key in the radix tree.
+ * @table:    Called on each table of the radix tree itself. Receives the
+ *            physical address of the page containing the table.
  *
  * 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 (*key)(unsigned long key);
+	int (*table)(phys_addr_t phys);

Naming is hard ;-)

Quoted 2 lines
include/linux/kho_radix_tree.h +0 -0
 };
 
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#22 lore raw

Re: [PATCH 04/12] kho: add callback for table pages

Quoted 9 lines · Mike Rapoport
Quoted 8 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO memory preservation radix tree does not mark the table pages themselves as scratch. This is done to avoid a circular dependency where preserving a page can lead of allocating other preserved pages. This means any walker looking for free ranges of memory outside of scratch areas will ignore the table

Quoted 3 lines
Quoted 1 line

Add a table callback that is invoked for each table page. The callback

A sentence why a table callback helps would be nice here :)

The main reason is that a later patch will create a radix tree for short use and will need to destroy it afterwards.

Will add that here.

Quoted 20 lines
Quoted 20 lines

is given the physical address of the table page.

---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 12 ++++++++++++
 2 files changed, 15 insertions(+)
include/linux/kho_radix_tree.h +2 -0
index 030da6399d28..fe7151d89361 100644
@@ -37,12 +37,15 @@ struct kho_radix_tree {
 /**
  * struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
  * @key:      Called on each present key in the radix tree.
+ * @table:    Called on each table of the radix tree itself. Receives the
+ *            physical address of the page containing the table.
  *
Quoted 8 lines

include/linux/kho_radix_tree.h struct kho_radix_tree { · line 48

Quoted 6 lines
include/linux/kho_radix_tree.h +1 -0
  * 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 (*key)(unsigned long key);
+	int (*table)(phys_addr_t phys);

Naming is hard ;-)

Yes :-/

Quoted 3 lines
Quoted 3 lines
include/linux/kho_radix_tree.h +0 -0
 };
 
Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#23 lore raw

Re: [PATCH 04/12] kho: add callback for table pages

Quoted 11 lines · Pratyush Yadav
Quoted 9 lines · Mike Rapoport
Quoted 8 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO memory preservation radix tree does not mark the table pages themselves as scratch. This is done to avoid a circular dependency where preserving a page can lead of allocating other preserved pages. This means any walker looking for free ranges of memory outside of scratch areas will ignore the table

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Add a table callback that is invoked for each table page. The callback

A sentence why a table callback helps would be nice here :)

The main reason is that a later patch will create a radix tree for short use and will need to destroy it afterwards.

This was meant for patch 7.

The reason for this one is that kho_extend_scratch() needs to exclude table pages from its free ranges. Will add it.

Quoted 7 lines

Will add that here.

Quoted 4 lines
Quoted 4 lines

is given the physical address of the table page.

Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#24 lore raw

PATCH 5/12 kho: add data argument to radix walk callback

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add an opaque data pointer argument to kho_radix_walk_cb_t. This can be used for callers to pass extra information to the callback.

---
 include/linux/kho_radix_tree.h     |  8 ++++----
 kernel/liveupdate/kexec_handover.c | 24 +++++++++++++-----------
 2 files changed, 17 insertions(+), 15 deletions(-)
include/linux/kho_radix_tree.h +4 -4
index fe7151d89361..6c0f7d82716b 100644
@@ -44,8 +44,8 @@ struct kho_radix_tree {
  * return value is directly returned to the caller.
  */
 struct kho_radix_walk_cb {
-	int (*key)(unsigned long key);
-	int (*table)(phys_addr_t phys);
+	int (*key)(unsigned long key, void *data);
+	int (*table)(phys_addr_t phys, void *data);
 };
 
 #ifdef CONFIG_KEXEC_HANDOVER
@@ -53,7 +53,7 @@ struct kho_radix_walk_cb {
 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,
-			const struct kho_radix_walk_cb *cb);
+			const struct kho_radix_walk_cb *cb, void *data);
 
 #else  /* #ifdef CONFIG_KEXEC_HANDOVER */
 
@@ -66,7 +66,7 @@ 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,
-				      const struct kho_radix_walk_cb *cb)
+				      const struct kho_radix_walk_cb *cb, void *data)
 {
 	return -EOPNOTSUPP;
 }
kernel/liveupdate/kexec_handover.c +13 -11
index 94ca831b41c9..d0a4f78eccfe 100644
@@ -267,14 +267,14 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
 static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
-			       const struct kho_radix_walk_cb *cb)
+			       const struct kho_radix_walk_cb *cb, void *data)
 {
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
 	if (cb->table) {
-		err = cb->table(virt_to_phys(leaf));
+		err = cb->table(virt_to_phys(leaf), data);
 		if (err)
 			return err;
 	}
@@ -283,7 +283,7 @@ static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 		return 0;
 
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb->key(key | i);
+		err = cb->key(key | i, data);
 		if (err)
 			return err;
 	}
@@ -293,7 +293,7 @@ static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 
 static int __kho_radix_walk_tree(struct kho_radix_node *root,
 				 unsigned int level, unsigned long start,
-				 const struct kho_radix_walk_cb *cb)
+				 const struct kho_radix_walk_cb *cb, void *data)
 {
 	struct kho_radix_node *node;
 	struct kho_radix_leaf *leaf;
@@ -302,7 +302,7 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 	int err;
 
 	if (cb->table) {
-		err = cb->table(virt_to_phys(root));
+		err = cb->table(virt_to_phys(root), data);
 		if (err)
 			return err;
 	}
@@ -323,10 +323,10 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 			 * node is pointing to the level 0 bitmap.
 			 */
 			leaf = (struct kho_radix_leaf *)node;
-			err = kho_radix_walk_leaf(leaf, key, cb);
+			err = kho_radix_walk_leaf(leaf, key, cb, data);
 		} else {
 			err  = __kho_radix_walk_tree(node, level - 1,
-						     key, cb);
+						     key, cb, data);
 		}
 
 		if (err)
@@ -340,6 +340,7 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
  * kho_radix_walk_tree - Traverses the radix tree and calls a callback for each key.
  * @tree: A pointer to the KHO radix tree to walk.
  * @cb:   Set of callbacks to be invoked during the tree walk.
+ * @data: Opaque data pointer passed to each callback in @cb.
  *
  * This function walks the radix tree, searching from the top level down to the
  * lowest level (level 0), invoking the appropriate callbacks.
@@ -348,14 +349,15 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
  *         value from the callback that stopped the walk.
  */
 int kho_radix_walk_tree(struct kho_radix_tree *tree,
-			const struct kho_radix_walk_cb *cb)
+			const struct kho_radix_walk_cb *cb, void *data)
 {
 	if (WARN_ON_ONCE(!tree->root))
 		return -EINVAL;
 
 	guard(mutex)(&tree->lock);
 
-	return __kho_radix_walk_tree(tree->root, KHO_TREE_MAX_DEPTH - 1, 0, cb);
+	return __kho_radix_walk_tree(tree->root, KHO_TREE_MAX_DEPTH - 1, 0, cb,
+				     data);
 }
 EXPORT_SYMBOL_GPL(kho_radix_walk_tree);
 
@@ -501,7 +503,7 @@ static struct page *__init kho_get_preserved_page(phys_addr_t phys,
 	return pfn_to_page(pfn);
 }
 
-static int __init kho_preserved_memory_reserve(unsigned long key)
+static int __init kho_preserved_memory_reserve(unsigned long key, void *data)
 {
 	union kho_page_info info;
 	struct page *page;
@@ -1392,7 +1394,7 @@ static int __init kho_mem_retrieve(const void *fdt)
 
 	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));
 	mutex_init(&kho_in.radix_tree.lock);
-	return kho_radix_walk_tree(&kho_in.radix_tree, &cb);
+	return kho_radix_walk_tree(&kho_in.radix_tree, &cb, NULL);
 }
 
 static __init int kho_out_fdt_setup(void)
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#25 lore raw

Re: [PATCH 05/12] kho: add data argument to radix walk callback

Quoted 4 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add an opaque data pointer argument to kho_radix_walk_cb_t. This can be used for callers to pass extra information to the callback.

Nit: ^by IMHO

Quoted 6 lines
---
 include/linux/kho_radix_tree.h     |  8 ++++----
 kernel/liveupdate/kexec_handover.c | 24 +++++++++++++-----------
 2 files changed, 17 insertions(+), 15 deletions(-)
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#26 lore raw

Re: [PATCH 05/12] kho: add data argument to radix walk callback

Quoted 7 lines · Mike Rapoport
Quoted 4 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add an opaque data pointer argument to kho_radix_walk_cb_t. This can be used for callers to pass extra information to the callback.

Nit: ^by IMHO

ACK, makes sense.

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer Reviewed-by on v1 5/12
#27 lore raw

Re: [PATCH 05/12] kho: add data argument to radix walk callback

In reply to Pratyush Yadav
Quoted 10 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add an opaque data pointer argument to kho_radix_walk_cb_t. This can be used for callers to pass extra information to the callback.

---
 include/linux/kho_radix_tree.h     |  8 ++++----
 kernel/liveupdate/kexec_handover.c | 24 +++++++++++++-----------
 2 files changed, 17 insertions(+), 15 deletions(-)
Quoted 142 lines
include/linux/kho_radix_tree.h +4 -4
index fe7151d89361..6c0f7d82716b 100644
@@ -44,8 +44,8 @@ struct kho_radix_tree {
  * return value is directly returned to the caller.
  */
 struct kho_radix_walk_cb {
-	int (*key)(unsigned long key);
-	int (*table)(phys_addr_t phys);
+	int (*key)(unsigned long key, void *data);
+	int (*table)(phys_addr_t phys, void *data);
 };
 
 #ifdef CONFIG_KEXEC_HANDOVER
@@ -53,7 +53,7 @@ struct kho_radix_walk_cb {
 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,
-			const struct kho_radix_walk_cb *cb);
+			const struct kho_radix_walk_cb *cb, void *data);
 
 #else  /* #ifdef CONFIG_KEXEC_HANDOVER */
 
@@ -66,7 +66,7 @@ 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,
-				      const struct kho_radix_walk_cb *cb)
+				      const struct kho_radix_walk_cb *cb, void *data)
 {
 	return -EOPNOTSUPP;
 }
kernel/liveupdate/kexec_handover.c +13 -11
index 94ca831b41c9..d0a4f78eccfe 100644
@@ -267,14 +267,14 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
 static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
-			       const struct kho_radix_walk_cb *cb)
+			       const struct kho_radix_walk_cb *cb, void *data)
 {
 	unsigned long *bitmap = (unsigned long *)leaf;
 	unsigned int i;
 	int err;
 
 	if (cb->table) {
-		err = cb->table(virt_to_phys(leaf));
+		err = cb->table(virt_to_phys(leaf), data);
 		if (err)
 			return err;
 	}
@@ -283,7 +283,7 @@ static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 		return 0;
 
 	for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) {
-		err = cb->key(key | i);
+		err = cb->key(key | i, data);
 		if (err)
 			return err;
 	}
@@ -293,7 +293,7 @@ static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 
 static int __kho_radix_walk_tree(struct kho_radix_node *root,
 				 unsigned int level, unsigned long start,
-				 const struct kho_radix_walk_cb *cb)
+				 const struct kho_radix_walk_cb *cb, void *data)
 {
 	struct kho_radix_node *node;
 	struct kho_radix_leaf *leaf;
@@ -302,7 +302,7 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 	int err;
 
 	if (cb->table) {
-		err = cb->table(virt_to_phys(root));
+		err = cb->table(virt_to_phys(root), data);
 		if (err)
 			return err;
 	}
@@ -323,10 +323,10 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
 			 * node is pointing to the level 0 bitmap.
 			 */
 			leaf = (struct kho_radix_leaf *)node;
-			err = kho_radix_walk_leaf(leaf, key, cb);
+			err = kho_radix_walk_leaf(leaf, key, cb, data);
 		} else {
 			err  = __kho_radix_walk_tree(node, level - 1,
-						     key, cb);
+						     key, cb, data);
 		}
 
 		if (err)
@@ -340,6 +340,7 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
  * kho_radix_walk_tree - Traverses the radix tree and calls a callback for each key.
  * @tree: A pointer to the KHO radix tree to walk.
  * @cb:   Set of callbacks to be invoked during the tree walk.
+ * @data: Opaque data pointer passed to each callback in @cb.
  *
  * This function walks the radix tree, searching from the top level down to the
  * lowest level (level 0), invoking the appropriate callbacks.
@@ -348,14 +349,15 @@ static int __kho_radix_walk_tree(struct kho_radix_node *root,
  *         value from the callback that stopped the walk.
  */
 int kho_radix_walk_tree(struct kho_radix_tree *tree,
-			const struct kho_radix_walk_cb *cb)
+			const struct kho_radix_walk_cb *cb, void *data)
 {
 	if (WARN_ON_ONCE(!tree->root))
 		return -EINVAL;
 
 	guard(mutex)(&tree->lock);
 
-	return __kho_radix_walk_tree(tree->root, KHO_TREE_MAX_DEPTH - 1, 0, cb);
+	return __kho_radix_walk_tree(tree->root, KHO_TREE_MAX_DEPTH - 1, 0, cb,
+				     data);
 }
 EXPORT_SYMBOL_GPL(kho_radix_walk_tree);
 
@@ -501,7 +503,7 @@ static struct page *__init kho_get_preserved_page(phys_addr_t phys,
 	return pfn_to_page(pfn);
 }
 
-static int __init kho_preserved_memory_reserve(unsigned long key)
+static int __init kho_preserved_memory_reserve(unsigned long key, void *data)
 {
 	union kho_page_info info;
 	struct page *page;
@@ -1392,7 +1394,7 @@ static int __init kho_mem_retrieve(const void *fdt)
 
 	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));
 	mutex_init(&kho_in.radix_tree.lock);
-	return kho_radix_walk_tree(&kho_in.radix_tree, &cb);
+	return kho_radix_walk_tree(&kho_in.radix_tree, &cb, NULL);
 }
 
 static __init int kho_out_fdt_setup(void)
Signature · 1 line
2.54.0.545.g6539524ca2-goog
author maintainer
#28 lore raw

PATCH 6/12 kho: allow early-boot usage of the KHO radix tree

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree allocates memory for table pages from the buddy allocator using get_zeroed_page(). This is not available in early boot when memblock is still active.

Using the radix tree in early boot is useful for KHO to track metadata about its memory. One such example is for tracking free blocks for memory allocation when scratch runs out of space. This feature will be added in the following commits.

Add kho_radix_{alloc,free}_node() which allocate and free the table pages. They use slab_is_available() to decide which allocator to use. While slab_is_available() indicates availability of the slab allocator, it gets initialized right before buddy so it serves the same practical purpose.

---
 kernel/liveupdate/kexec_handover.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)
kernel/liveupdate/kexec_handover.c +22 -2
index d0a4f78eccfe..47f7c4a2865e 100644
@@ -143,6 +143,26 @@ static unsigned long kho_radix_get_table_index(unsigned long key,
 	return (key >> s) % (1 << KHO_TABLE_SIZE_LOG2);
 }
 
+static void __ref *kho_radix_alloc_node(void)
+{
+	struct kho_radix_node *node;
+
+	if (slab_is_available())
+		node = (struct kho_radix_node *)get_zeroed_page(GFP_KERNEL);
+	else
+		node = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+
+	return node;
+}
+
+static void __ref kho_radix_free_node(struct kho_radix_node *node)
+{
+	if (slab_is_available())
+		free_page((unsigned long)node);
+	else
+		memblock_free(node, PAGE_SIZE);
+}
+
 /**
  * kho_radix_add_key - Add a key to the radix tree.
  * @tree: The KHO radix tree.
@@ -183,7 +203,7 @@ int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
 		}
 
 		/* Next node is empty, create a new node for it */
-		new_node = (struct kho_radix_node *)get_zeroed_page(GFP_KERNEL);
+		new_node = kho_radix_alloc_node();
 		if (!new_node) {
 			err = -ENOMEM;
 			goto err_free_nodes;
@@ -214,7 +234,7 @@ int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
 err_free_nodes:
 	for (i = KHO_TREE_MAX_DEPTH - 1; i > 0; i--) {
 		if (intermediate_nodes[i])
-			free_page((unsigned long)intermediate_nodes[i]);
+			kho_radix_free_node(intermediate_nodes[i]);
 	}
 	if (anchor_node)
 		anchor_node->table[anchor_idx] = 0;
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#29 lore raw

Re: [PATCH 06/12] kho: allow early-boot usage of the KHO radix tree

Quoted 11 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree allocates memory for table pages from the buddy allocator using get_zeroed_page(). This is not available in early boot when memblock is still active.

Using the radix tree in early boot is useful for KHO to track metadata about its memory. One such example is for tracking free blocks for memory allocation when scratch runs out of space. This feature will be added in the following commits.

Quoted 4 lines

Add kho_radix_{alloc,free}_node() which allocate and free the table pages. They use slab_is_available() to decide which allocator to use. While slab_is_available() indicates availability of the slab allocator, it gets initialized right before buddy so it serves the same practical

^ after?

Quoted 6 lines

purpose.

---
 kernel/liveupdate/kexec_handover.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#30 lore raw

Re: [PATCH 06/12] kho: allow early-boot usage of the KHO radix tree

Quoted 12 lines · Mike Rapoport
Quoted 11 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree allocates memory for table pages from the buddy allocator using get_zeroed_page(). This is not available in early boot when memblock is still active.

Using the radix tree in early boot is useful for KHO to track metadata about its memory. One such example is for tracking free blocks for memory allocation when scratch runs out of space. This feature will be added in the following commits.

Quoted 6 lines
Quoted 4 lines

Add kho_radix_{alloc,free}_node() which allocate and free the table pages. They use slab_is_available() to decide which allocator to use. While slab_is_available() indicates availability of the slab allocator, it gets initialized right before buddy so it serves the same practical

^ after?

ACK, will fix.

Quoted 7 lines
Quoted 7 lines

purpose.

---
 kernel/liveupdate/kexec_handover.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)
Signature · 2 lines
Regards,
Pratyush Yadav
maintainer Reviewed-by on v1 6/12
#31 lore raw

Re: [PATCH 06/12] kho: allow early-boot usage of the KHO radix tree

In reply to Pratyush Yadav
Quoted 11 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

The KHO radix tree allocates memory for table pages from the buddy allocator using get_zeroed_page(). This is not available in early boot when memblock is still active.

Using the radix tree in early boot is useful for KHO to track metadata about its memory. One such example is for tracking free blocks for memory allocation when scratch runs out of space. This feature will be added in the following commits.

Quoted 7 lines

Add kho_radix_{alloc,free}_node() which allocate and free the table pages. They use slab_is_available() to decide which allocator to use. While slab_is_available() indicates availability of the slab allocator, it gets initialized right before buddy so it serves the same practical purpose.

Quoted 56 lines
---
 kernel/liveupdate/kexec_handover.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)
kernel/liveupdate/kexec_handover.c +22 -2
index d0a4f78eccfe..47f7c4a2865e 100644
@@ -143,6 +143,26 @@ static unsigned long kho_radix_get_table_index(unsigned long key,
 	return (key >> s) % (1 << KHO_TABLE_SIZE_LOG2);
 }
 
+static void __ref *kho_radix_alloc_node(void)
+{
+	struct kho_radix_node *node;
+
+	if (slab_is_available())
+		node = (struct kho_radix_node *)get_zeroed_page(GFP_KERNEL);
+	else
+		node = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+
+	return node;
+}
+
+static void __ref kho_radix_free_node(struct kho_radix_node *node)
+{
+	if (slab_is_available())
+		free_page((unsigned long)node);
+	else
+		memblock_free(node, PAGE_SIZE);
+}
+
 /**
  * kho_radix_add_key - Add a key to the radix tree.
  * @tree: The KHO radix tree.
@@ -183,7 +203,7 @@ int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
 		}
 
 		/* Next node is empty, create a new node for it */
-		new_node = (struct kho_radix_node *)get_zeroed_page(GFP_KERNEL);
+		new_node = kho_radix_alloc_node();
 		if (!new_node) {
 			err = -ENOMEM;
 			goto err_free_nodes;
@@ -214,7 +234,7 @@ int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
 err_free_nodes:
 	for (i = KHO_TREE_MAX_DEPTH - 1; i > 0; i--) {
 		if (intermediate_nodes[i])
-			free_page((unsigned long)intermediate_nodes[i]);
+			kho_radix_free_node(intermediate_nodes[i]);
 	}
 	if (anchor_node)
 		anchor_node->table[anchor_idx] = 0;
Signature · 1 line
2.54.0.545.g6539524ca2-goog
author maintainer
#32 lore raw

PATCH 7/12 kho: allow destroying KHO radix tree

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add kho_radix_destroy_tree() which allows destroying the radix tree and freeing all its pages.

---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 34 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)
include/linux/kho_radix_tree.h +3 -0
index 6c0f7d82716b..617395a6647a 100644
@@ -54,6 +54,7 @@ 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,
 			const struct kho_radix_walk_cb *cb, void *data);
+void kho_radix_destroy_tree(struct kho_radix_tree *tree);
 
 #else  /* #ifdef CONFIG_KEXEC_HANDOVER */
 
@@ -71,6 +72,8 @@ static inline int kho_radix_walk_tree(struct kho_radix_tree *tree,
 	return -EOPNOTSUPP;
 }
 
+static inline void kho_radix_destroy_tree(struct kho_radix_tree *tree) { }
+
 #endif /* #ifdef CONFIG_KEXEC_HANDOVER */
 
 #endif	/* _LINUX_KHO_RADIX_TREE_H */
kernel/liveupdate/kexec_handover.c +34 -0
index 47f7c4a2865e..29479534f65d 100644
@@ -286,6 +286,40 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
+static void __kho_radix_destroy_tree(struct kho_radix_node *root,
+				     unsigned int level)
+{
+	unsigned long i;
+
+	if (level == 0) {
+		kho_radix_free_node(root);
+		return;
+	}
+
+	for (i = 0; i < PAGE_SIZE / sizeof(phys_addr_t); i++) {
+		if (root->table[i])
+			__kho_radix_destroy_tree(phys_to_virt(root->table[i]),
+						 level - 1);
+	}
+
+	kho_radix_free_node(root);
+}
+
+/**
+ * kho_radix_destroy_tree - Destroy the radix tree
+ * @tree: The radix tree to destroy
+ *
+ * Walk @tree and free all its nodes.
+ */
+void kho_radix_destroy_tree(struct kho_radix_tree *tree)
+{
+	if (!tree->root)
+		return;
+
+	__kho_radix_destroy_tree(tree->root, KHO_TREE_MAX_DEPTH - 1);
+}
+EXPORT_SYMBOL_GPL(kho_radix_destroy_tree);
+
 static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 			       const struct kho_radix_walk_cb *cb, void *data)
 {
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#33 lore raw

Re: [PATCH 07/12] kho: allow destroying KHO radix tree

Quoted 4 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add kho_radix_destroy_tree() which allows destroying the radix tree and freeing all its pages.

A sentence why it Will be useful would be nice.

Quoted 5 lines
---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 34 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)
Signature · 2 lines
Sincerely yours,
Mike.
maintainer Reviewed-by on v1 7/12
#34 lore raw

Re: [PATCH 07/12] kho: allow destroying KHO radix tree

In reply to Pratyush Yadav
Quoted 10 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add kho_radix_destroy_tree() which allows destroying the radix tree and freeing all its pages.

---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 34 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

Generally, in Linux, recursion is avoided due to statically sized kernel stacks. However, here we are bound by a relatively shallow KHO tree, and kho_radix_walk_tree() is already recursive, so I think it is alright. We just need to be mindful of local variable usage (frame sizes) within these recursive functions.

Quoted 70 lines
include/linux/kho_radix_tree.h +3 -0
index 6c0f7d82716b..617395a6647a 100644
@@ -54,6 +54,7 @@ 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,
 			const struct kho_radix_walk_cb *cb, void *data);
+void kho_radix_destroy_tree(struct kho_radix_tree *tree);
 
 #else  /* #ifdef CONFIG_KEXEC_HANDOVER */
 
@@ -71,6 +72,8 @@ static inline int kho_radix_walk_tree(struct kho_radix_tree *tree,
 	return -EOPNOTSUPP;
 }
 
+static inline void kho_radix_destroy_tree(struct kho_radix_tree *tree) { }
+
 #endif /* #ifdef CONFIG_KEXEC_HANDOVER */
 
 #endif	/* _LINUX_KHO_RADIX_TREE_H */
kernel/liveupdate/kexec_handover.c +34 -0
index 47f7c4a2865e..29479534f65d 100644
@@ -286,6 +286,40 @@ void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key)
 }
 EXPORT_SYMBOL_GPL(kho_radix_del_key);
 
+static void __kho_radix_destroy_tree(struct kho_radix_node *root,
+				     unsigned int level)
+{
+	unsigned long i;
+
+	if (level == 0) {
+		kho_radix_free_node(root);
+		return;
+	}
+
+	for (i = 0; i < PAGE_SIZE / sizeof(phys_addr_t); i++) {
+		if (root->table[i])
+			__kho_radix_destroy_tree(phys_to_virt(root->table[i]),
+						 level - 1);
+	}
+
+	kho_radix_free_node(root);
+}
+
+/**
+ * kho_radix_destroy_tree - Destroy the radix tree
+ * @tree: The radix tree to destroy
+ *
+ * Walk @tree and free all its nodes.
+ */
+void kho_radix_destroy_tree(struct kho_radix_tree *tree)
+{
+	if (!tree->root)
+		return;
+
+	__kho_radix_destroy_tree(tree->root, KHO_TREE_MAX_DEPTH - 1);
+}
+EXPORT_SYMBOL_GPL(kho_radix_destroy_tree);
+
 static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, unsigned long key,
 			       const struct kho_radix_walk_cb *cb, void *data)
 {
Signature · 1 line
2.54.0.545.g6539524ca2-goog
author maintainer
#35 lore raw

Re: [PATCH 07/12] kho: allow destroying KHO radix tree

Quoted 12 lines · Pasha Tatashin
Quoted 10 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Add kho_radix_destroy_tree() which allows destroying the radix tree and freeing all its pages.

---
 include/linux/kho_radix_tree.h     |  3 +++
 kernel/liveupdate/kexec_handover.c | 34 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)
Quoted 5 lines

Generally, in Linux, recursion is avoided due to statically sized kernel stacks. However, here we are bound by a relatively shallow KHO tree, and kho_radix_walk_tree() is already recursive, so I think it is alright. We just need to be mindful of local variable usage (frame sizes) within these recursive functions.

Yep, recursion is strictly bounded and the depth is no worse than any page table walkers for example.

Quoted 2 lines

Thanks!

Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#36 lore raw

PATCH 8/12 kho: add kho_radix_init_tree()

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Move the initialization logic of the radix tree into kho_radix_init_tree() instead of having users open-code it. Makes the boundaries cleaner and reduces code duplication when a new user of the radix tree will be added in a future commit.

---
 include/linux/kho_radix_tree.h     |  7 ++++++
 kernel/liveupdate/kexec_handover.c | 37 ++++++++++++++++++++++++++++--
 2 files changed, 42 insertions(+), 2 deletions(-)
include/linux/kho_radix_tree.h +7 -0
index 617395a6647a..c0840ecb230c 100644
@@ -54,6 +54,7 @@ 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,
 			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 */
@@ -72,6 +73,12 @@ static inline int kho_radix_walk_tree(struct kho_radix_tree *tree,
 	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 */
kernel/liveupdate/kexec_handover.c +35 -2
index 29479534f65d..1a04e089f779 100644
@@ -305,6 +305,34 @@ static void __kho_radix_destroy_tree(struct kho_radix_node *root,
 	kho_radix_free_node(root);
 }
 
+/**
+ * kho_radix_init_tree - initialize the radix tree.
+ * @tree:   the tree to initialize.
+ * @root:   root table of the radix tree.
+ *
+ * Initialize the radix tree with the given root node. If root is %NULL, an
+ * empty root table is allocated. If root is not %NULL, it is the caller's
+ * responsibility to make sure the root is valid and in the correct format.
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+int kho_radix_init_tree(struct kho_radix_tree *tree, struct kho_radix_node *root)
+{
+	/* Already initialized. */
+	if (tree->root)
+		return 0;
+
+	if (!root)
+		root = kho_radix_alloc_node();
+	if (!root)
+		return -ENOMEM;
+
+	tree->root = root;
+	mutex_init(&tree->lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kho_radix_init_tree);
+
 /**
  * kho_radix_destroy_tree - Destroy the radix tree
  * @tree: The radix tree to destroy
@@ -1445,9 +1473,14 @@ static int __init kho_mem_retrieve(const void *fdt)
 	const struct kho_radix_walk_cb cb = {
 		.key = kho_preserved_memory_reserve,
 	};
+	phys_addr_t mem_map_phys;
+	int err;
+
+	mem_map_phys = kho_get_mem_map_phys(fdt);
+	err = kho_radix_init_tree(&kho_in.radix_tree, phys_to_virt(mem_map_phys));
+	if (err)
+		return err;
 
-	kho_in.radix_tree.root = phys_to_virt(kho_get_mem_map_phys(fdt));
-	mutex_init(&kho_in.radix_tree.lock);
 	return kho_radix_walk_tree(&kho_in.radix_tree, &cb, NULL);
 }
 
Signature · 1 line
2.54.0.545.g6539524ca2-goog
#37 lore raw

Re: [PATCH 08/12] kho: add kho_radix_init_tree()

Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Move the initialization logic of the radix tree into kho_radix_init_tree() instead of having users open-code it. Makes the boundaries cleaner and reduces code duplication when a new user of the radix tree will be added in a future commit.

Consider using kho_radix_init_tree() in kho_init() as well. This will also remove the kzalloc() one-off use. Similar for kho_radix_destroy_tree().

Best,
Jork

author maintainer
#38 lore raw

Re: [PATCH 08/12] kho: add kho_radix_init_tree()

Quoted 11 lines · Jork Loeser
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Move the initialization logic of the radix tree into kho_radix_init_tree() instead of having users open-code it. Makes the boundaries cleaner and reduces code duplication when a new user of the radix tree will be added in a future commit.

Consider using kho_radix_init_tree() in kho_init() as well. This will also remove the kzalloc() one-off use. Similar for kho_radix_destroy_tree().

Good point. Will do.

Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#39 lore raw

PATCH 9/12 memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

---

Notes:
Checkpatch complains about no space after MEMBLOCK_KHO_SCRATCH_EXT in the declaration, but doing so makes it nicely align with all the other numbers. Mike, if you'd like I can add some whitespace.

 include/linux/memblock.h | 10 ++++++++++
 mm/memblock.c            | 41 ++++++++++++++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 6 deletions(-)
include/linux/memblock.h +10 -0
index 5afcd99aa8c1..4f535ca4947a 100644
@@ -51,6 +51,9 @@ 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_KHO_SCRATCH_EXT: same as MEMBLOCK_KHO_SCRATCH but was discovered at
+ * boot time by finding gaps in preserved memory instead of being passed from
+ * previous kernel. Does not get passed to the next kernel.
  */
 enum memblock_flags {
 	MEMBLOCK_NONE		= 0x0,	/* No special request */
@@ -61,6 +64,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_KHO_SCRATCH_EXT= 0x80, /* extended scratch memory for KHO */
 };
 
 /**
@@ -157,6 +161,7 @@ int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
 int memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t size);
 int memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size);
 int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size);
+int memblock_mark_kho_scratch_ext(phys_addr_t base, phys_addr_t size);
 int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size);
 
 void memblock_free(void *ptr, size_t size);
@@ -304,6 +309,11 @@ static inline bool memblock_is_kho_scratch(struct memblock_region *m)
 	return m->flags & MEMBLOCK_KHO_SCRATCH;
 }
 
+static inline bool memblock_is_kho_scratch_ext(struct memblock_region *m)
+{
+	return m->flags & MEMBLOCK_KHO_SCRATCH_EXT;
+}
+
 int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
 			    unsigned long  *end_pfn);
 void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
mm/memblock.c +35 -6

72 lines not on this page · raw message

Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#40 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 10 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

Why there's a need to differentiate SCRATCH and SCRATCH_EXT? SCRATCH (I still hate the name) means "memory memblock can safely use for the allocations". Initially this memory comes from the reservations in the first kernel, but if the second kernel can find more memory to extend it, why that additional memory should be treated differently?

Quoted 11 lines

---

Notes:
Checkpatch complains about no space after MEMBLOCK_KHO_SCRATCH_EXT in the declaration, but doing so makes it nicely align with all the other numbers. Mike, if you'd like I can add some whitespace.

 include/linux/memblock.h | 10 ++++++++++
 mm/memblock.c            | 41 ++++++++++++++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 6 deletions(-)
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#41 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 12 lines · Mike Rapoport
Quoted 10 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

Quoted 5 lines

Why there's a need to differentiate SCRATCH and SCRATCH_EXT? SCRATCH (I still hate the name) means "memory memblock can safely use for the allocations". Initially this memory comes from the reservations in the first kernel, but if the second kernel can find more memory to extend it, why that additional memory should be treated differently?

Two reasons:

1. We mark SCRATCH as MIGRATE_CMA. We don't want to do that for SCRATCH_EXT since this memory can be used for non-movable allocations.

2. Gigantic (1G) huge pages can not be allocated from scratch. They can be preserved memory and thus should not be allocated from SCRATCH. See patch 12 that does allocations for gigantic huge pages only from SCRATCH_EXT.

I will add this in the commit message for the next version.

Naming is hard, so if you have any better names I'm all ears :-)

Quoted 12 lines
Quoted 12 lines

---

Notes:
Checkpatch complains about no space after MEMBLOCK_KHO_SCRATCH_EXT in the declaration, but doing so makes it nicely align with all the other numbers. Mike, if you'd like I can add some whitespace.

 include/linux/memblock.h | 10 ++++++++++
 mm/memblock.c            | 41 ++++++++++++++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 6 deletions(-)
Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#42 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 9 lines · Pratyush Yadav
Quoted 7 lines · Mike Rapoport
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

Quoted 7 lines
Quoted 7 lines
Quoted 4 lines

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

Why there's a need to differentiate SCRATCH and SCRATCH_EXT? SCRATCH (I still hate the name) means "memory memblock can safely use for

+1000

I also strongly dislike this name and mentioned it in another thread earlier today.

If we ever decide to s/scratch/something-else/ globally, that should be a separate cleanup effort. However, since we are introducing a brand new flag here, we can discuss a better name for the _ext portion to avoid overloading the "scratch" concept.

Quoted 10 lines
Quoted 3 lines

the allocations". Initially this memory comes from the reservations in the first kernel, but if the second kernel can find more memory to extend it, why that additional memory should be treated differently?

Two reasons:

1. We mark SCRATCH as MIGRATE_CMA. We don't want to do that for SCRATCH_EXT since this memory can be used for non-movable allocations.

Quoted 8 lines

2. Gigantic (1G) huge pages can not be allocated from scratch. They can be preserved memory and thus should not be allocated from SCRATCH. See patch 12 that does allocations for gigantic huge pages only from SCRATCH_EXT.

I will add this in the commit message for the next version.

Naming is hard, so if you have any better names I'm all ears :-)

IMO, this scratch_ext is not "scratch" in the traditional KHO sense at all. The traditional KHO scratch is what is passed from kernel to kernel and is guaranteed to contain zero preserved memory. This new memory is not passed from kernel to kernel and can contain preserved memory at runtime. It's essentially just memory that we identify as currently unpreserved and release early to the system.

If we want to keep the naming aligned with the existing codebase for now:
MEMBLOCK_KHO_SCRATCH -> original scratch
MEMBLOCK_KHO_UNPRESERVED -> for the new memory (instead of SCRATCH_EXT)

Alternatively, if we do want to tackle the global rename of "scratch" later:
MEMBLOCK_KHO_BOOTSTRAP -> for the original scratch
MEMBLOCK_KHO_UNPRESERVED -> for this new dynamic memory

What do you think?

Pasha

Quoted 17 lines
Quoted 13 lines
Quoted 13 lines

---

Notes:
Checkpatch complains about no space after MEMBLOCK_KHO_SCRATCH_EXT in the declaration, but doing so makes it nicely align with all the other numbers. Mike, if you'd like I can add some whitespace.

 include/linux/memblock.h | 10 ++++++++++
 mm/memblock.c            | 41 ++++++++++++++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 6 deletions(-)
Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#43 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 54 lines · Pasha Tatashin
Quoted 9 lines · Pratyush Yadav
Quoted 7 lines · Mike Rapoport
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

Quoted 7 lines
Quoted 7 lines
Quoted 4 lines

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

Why there's a need to differentiate SCRATCH and SCRATCH_EXT? SCRATCH (I still hate the name) means "memory memblock can safely use for

+1000

I also strongly dislike this name and mentioned it in another thread earlier today.

If we ever decide to s/scratch/something-else/ globally, that should be a separate cleanup effort. However, since we are introducing a brand new flag here, we can discuss a better name for the _ext portion to avoid overloading the "scratch" concept.

Quoted 10 lines
Quoted 3 lines

the allocations". Initially this memory comes from the reservations in the first kernel, but if the second kernel can find more memory to extend it, why that additional memory should be treated differently?

Two reasons:

1. We mark SCRATCH as MIGRATE_CMA. We don't want to do that for SCRATCH_EXT since this memory can be used for non-movable allocations.

Quoted 8 lines

2. Gigantic (1G) huge pages can not be allocated from scratch. They can be preserved memory and thus should not be allocated from SCRATCH. See patch 12 that does allocations for gigantic huge pages only from SCRATCH_EXT.

I will add this in the commit message for the next version.

Naming is hard, so if you have any better names I'm all ears :-)

IMO, this scratch_ext is not "scratch" in the traditional KHO sense at all. The traditional KHO scratch is what is passed from kernel to kernel and is guaranteed to contain zero preserved memory. This new memory is not passed from kernel to kernel and can contain preserved memory at runtime. It's essentially just memory that we identify as currently unpreserved and release early to the system.

Quoted 3 lines

If we want to keep the naming aligned with the existing codebase for now:
MEMBLOCK_KHO_SCRATCH -> original scratch
MEMBLOCK_KHO_UNPRESERVED -> for the new memory (instead of SCRATCH_EXT)

UNPRESERVED sounds good to me. I will use that for the next revision unless Mike objects.

Quoted 4 lines

Alternatively, if we do want to tackle the global rename of "scratch" later:
MEMBLOCK_KHO_BOOTSTRAP -> for the original scratch
MEMBLOCK_KHO_UNPRESERVED -> for this new dynamic memory

Or perhaps BOOTMEM? I suppose either of the two are somewhat better than scratch.

Anyway, can we please do the SCRATCH rename as a separate series? I would like this series to not get muddled in the naming discussion. I will use UNPRESERVED for the new concept in v2 though.

Quoted 4 lines

What do you think?

Pasha

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#44 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 56 lines · Pratyush Yadav
Quoted 54 lines · Pasha Tatashin
Quoted 9 lines · Pratyush Yadav
Quoted 7 lines · Mike Rapoport
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

Quoted 7 lines
Quoted 7 lines
Quoted 4 lines

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

Why there's a need to differentiate SCRATCH and SCRATCH_EXT? SCRATCH (I still hate the name) means "memory memblock can safely use for

+1000

I also strongly dislike this name and mentioned it in another thread earlier today.

If we ever decide to s/scratch/something-else/ globally, that should be a separate cleanup effort. However, since we are introducing a brand new flag here, we can discuss a better name for the _ext portion to avoid overloading the "scratch" concept.

Quoted 10 lines
Quoted 3 lines

the allocations". Initially this memory comes from the reservations in the first kernel, but if the second kernel can find more memory to extend it, why that additional memory should be treated differently?

Two reasons:

1. We mark SCRATCH as MIGRATE_CMA. We don't want to do that for SCRATCH_EXT since this memory can be used for non-movable allocations.

Quoted 8 lines

2. Gigantic (1G) huge pages can not be allocated from scratch. They can be preserved memory and thus should not be allocated from SCRATCH. See patch 12 that does allocations for gigantic huge pages only from SCRATCH_EXT.

I will add this in the commit message for the next version.

Naming is hard, so if you have any better names I'm all ears :-)

IMO, this scratch_ext is not "scratch" in the traditional KHO sense at all. The traditional KHO scratch is what is passed from kernel to kernel and is guaranteed to contain zero preserved memory. This new memory is not passed from kernel to kernel and can contain preserved memory at runtime. It's essentially just memory that we identify as currently unpreserved and release early to the system.

Quoted 6 lines
Quoted 3 lines

If we want to keep the naming aligned with the existing codebase for now:
MEMBLOCK_KHO_SCRATCH -> original scratch
MEMBLOCK_KHO_UNPRESERVED -> for the new memory (instead of SCRATCH_EXT)

UNPRESERVED sounds good to me. I will use that for the next revision unless Mike objects.

Can we make it shorter? ;-)

UNPRESERVED makes sense, although I'd love to completely remove KHO_ notion and make the name reflect how it's used by memblock. I was toying with PREFERRED instead of SCRATCH, but it didn't feel right enough. With two of them that surely won't work :)

Quoted 6 lines
Quoted 3 lines

Alternatively, if we do want to tackle the global rename of "scratch" later:
MEMBLOCK_KHO_BOOTSTRAP -> for the original scratch
MEMBLOCK_KHO_UNPRESERVED -> for this new dynamic memory

Or perhaps BOOTMEM? I suppose either of the two are somewhat better than scratch.

Well, if we have BOOTMEM_HVO, we can have BOOTMEM_KHO as well :)

Quoted 1 line

Anyway, can we please do the SCRATCH rename as a separate series? I

Sure. We can continue bikeshedding in parallel.

Quoted 2 lines

would like this series to not get muddled in the naming discussion. I will use UNPRESERVED for the new concept in v2 though.

That might warrant v3 even if everything else is perfect :)

Quoted 3 lines
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#45 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 64 lines · Mike Rapoport
Quoted 56 lines · Pratyush Yadav
Quoted 54 lines · Pasha Tatashin
Quoted 9 lines · Pratyush Yadav
Quoted 7 lines · Mike Rapoport
Quoted 6 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

In the upcoming commits, the KHO will learn how to discover free blocks of memory by walking the KHO radix tree. It will then mark those regions as scratch to allow memory allocation in case scratch runs low.

Quoted 7 lines
Quoted 7 lines
Quoted 4 lines

To differentiate the extended scratch areas from the main scratch areas, introduce MEMBLOCK_KHO_SCRATCH_EXT. Use it when choosing memblock flags for allocations during scratch-only. Teach should_skip_region() to check for both flags before deciding if the region should be skipped.

Why there's a need to differentiate SCRATCH and SCRATCH_EXT? SCRATCH (I still hate the name) means "memory memblock can safely use for

+1000

I also strongly dislike this name and mentioned it in another thread earlier today.

If we ever decide to s/scratch/something-else/ globally, that should be a separate cleanup effort. However, since we are introducing a brand new flag here, we can discuss a better name for the _ext portion to avoid overloading the "scratch" concept.

Quoted 10 lines
Quoted 3 lines

the allocations". Initially this memory comes from the reservations in the first kernel, but if the second kernel can find more memory to extend it, why that additional memory should be treated differently?

Two reasons:

1. We mark SCRATCH as MIGRATE_CMA. We don't want to do that for SCRATCH_EXT since this memory can be used for non-movable allocations.

Quoted 8 lines

2. Gigantic (1G) huge pages can not be allocated from scratch. They can be preserved memory and thus should not be allocated from SCRATCH. See patch 12 that does allocations for gigantic huge pages only from SCRATCH_EXT.

I will add this in the commit message for the next version.

Naming is hard, so if you have any better names I'm all ears :-)

IMO, this scratch_ext is not "scratch" in the traditional KHO sense at all. The traditional KHO scratch is what is passed from kernel to kernel and is guaranteed to contain zero preserved memory. This new memory is not passed from kernel to kernel and can contain preserved memory at runtime. It's essentially just memory that we identify as currently unpreserved and release early to the system.

Quoted 6 lines
Quoted 3 lines

If we want to keep the naming aligned with the existing codebase for now:
MEMBLOCK_KHO_SCRATCH -> original scratch
MEMBLOCK_KHO_UNPRESERVED -> for the new memory (instead of SCRATCH_EXT)

UNPRESERVED sounds good to me. I will use that for the next revision unless Mike objects.

Quoted 6 lines

Can we make it shorter? ;-)

UNPRESERVED makes sense, although I'd love to completely remove KHO_ notion and make the name reflect how it's used by memblock. I was toying with PREFERRED instead of SCRATCH, but it didn't feel right enough. With two of them that surely won't work :)

I don't think you really can remove KHO_ notion. These memory regions only make sense on a KHO boot, and won't exist otherwise. And PREFERRED sounds like a suggestion/priority hint, not a hard limit. "With KHO boot, you can _only_ use PREFERRED memory", doesn't sound right...

I think MEMBLOCK_KHO_BOOTMEM for scratch and MEMBLOCK_KHO_NOPRESERVE (which I think is a tiny bit better than UNPRESERVED) for scratch_ext are my top picks. To make it shorter, perhaps MEMBLOCK_KHO_NOPRSRV, in similar fashion to RSRV_KERN?

Quoted 10 lines
Quoted 7 lines
Quoted 4 lines

Alternatively, if we do want to tackle the global rename of "scratch" later:
MEMBLOCK_KHO_BOOTSTRAP -> for the original scratch
MEMBLOCK_KHO_UNPRESERVED -> for this new dynamic memory

Or perhaps BOOTMEM? I suppose either of the two are somewhat better than scratch.

Well, if we have BOOTMEM_HVO, we can have BOOTMEM_KHO as well :)

Quoted 8 lines
Quoted 1 line

Anyway, can we please do the SCRATCH rename as a separate series? I

Sure. We can continue bikeshedding in parallel.

Quoted 2 lines

would like this series to not get muddled in the naming discussion. I will use UNPRESERVED for the new concept in v2 though.

That might warrant v3 even if everything else is perfect :)

I can live with that. As long as we can agree on the easy part (the code), I don't mind doing another version for the hard part (the naming) ;-)

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#46 lore raw

Re: [PATCH 09/12] memblock: introduce MEMBLOCK_KHO_SCRATCH_EXT

Quoted 21 lines · Pratyush Yadav
Quoted 8 lines · Mike Rapoport
Quoted 7 lines
Quoted 4 lines

If we want to keep the naming aligned with the existing codebase for now:
MEMBLOCK_KHO_SCRATCH -> original scratch
MEMBLOCK_KHO_UNPRESERVED -> for the new memory (instead of SCRATCH_EXT)

UNPRESERVED sounds good to me. I will use that for the next revision unless Mike objects.

Quoted 6 lines

Can we make it shorter? ;-)

UNPRESERVED makes sense, although I'd love to completely remove KHO_ notion and make the name reflect how it's used by memblock. I was toying with PREFERRED instead of SCRATCH, but it didn't feel right enough. With two of them that surely won't work :)

I don't think you really can remove KHO_ notion. These memory regions only make sense on a KHO boot, and won't exist otherwise. And PREFERRED sounds like a suggestion/priority hint, not a hard limit. "With KHO boot, you can _only_ use PREFERRED memory", doesn't sound right...

Quoted 4 lines

I think MEMBLOCK_KHO_BOOTMEM for scratch and MEMBLOCK_KHO_NOPRESERVE (which I think is a tiny bit better than UNPRESERVED) for scratch_ext are my top picks. To make it shorter, perhaps MEMBLOCK_KHO_NOPRSRV, in similar fashion to RSRV_KERN?

There are a couple of unrelated 'bootmem' things in the kernel, adding another one shouldn't hurt :)

I like MEMBLOCK_KHO_BOOTMEM and MEMBLOCK_KHO_NOPRSRV the most.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

would like this series to not get muddled in the naming discussion. I will use UNPRESERVED for the new concept in v2 though.

That might warrant v3 even if everything else is perfect :)

I can live with that. As long as we can agree on the easy part (the code), I don't mind doing another version for the hard part (the naming) ;-)

It makes sense to keep KHO_SCRATCH for now and use MEMBLOCK_KHO_NOPRSRV for the new one to begin with. And then we can ask an LLM do the renaming.

Quoted 3 lines
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#47 lore raw

PATCH 10/12 kho: extended scratch

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Motivation
==========

The scratch space is allocated by the first kernel in the KHO chain, and is reused by all subsequent kernels. The size of the space is either set via the commandline by the system administrator or by calculating the amount of memory used by the kernel and adding a multiplier. In either case, the scratch space is a heuristic and is liable to fill up and fail allocation if a kernel uses more memory than expected.

In addition, gigantic huge pages (usually 1 GiB) are allocated via memblock, and in a KHO boot that memory comes from the scratch space. In hypervisors it is common to dedicate a major part of the system's memory to gigantic hugepages for VM memory.

If this memory needs to come from scratch space, then scratch needs to be greater than the memory needed for huge pages, which is impractical. In addition, hugepages can be preserved memory. Allocating them from scratch violates the assumption that scratch contains no preserved memory.

Methodology
===========

Introduce extended scratch areas. These areas are discovered at boot by walking the preserved memory radix tree and looking for free blocks of memory. They then marked as scratch to allow allocations from them. This makes KHO more resilient to memory pressure and allows supporting huge page preservation.

Since the preserved memory radix tree mixes both physical address and order into a single key, and does not track table pages, it is difficult to identify free areas from it directly. Walk the tree and digest it down into another radix tree. The latter tracks blocks of KHO_EXT_SHIFT (1 GiB as of now) granularity. Then walk the digested tree and mark the areas between the present keys as scratch.

Performance
===========

The discovery algorithm traverses the preserved memory radix tree exactly once. While it does use memory for the digested radix tree, since the blocks are split by 1 GiB, a single bitmap with 4k pages can track up to 32 TiB of memory. So there are likely to be very few radix tree pages used in this tracking. For systems with all physical memory below 32 TiB, this should result in a total of 6 pages being used (KHO_TREE_MAX_DEPTH == 6).

An alternate way of achieving this would be to call kho_mem_retrieve() earlier in boot and mark all the KHO preservations as reserved. But that can blow up memblock.reserved with a bunch of 4K pages scattered everywhere, which will reduce performance of subsequent allocations. Since the free blocks are tracked in chunks of 1 GiB, this won't blow up memblock.memory as much.

Practical evaluation
====================

The testing is done on a x86_64 qemu VM running under KVM with 64G memory and 12 CPUs. The machine pre-allocates 50 1G pages.

Since the performance scales with how busy the radix tree is, tests are done with 2 preservation patterns: first with two 1M memfds, second with two 1G memfds, both using 4k pages.

Test case 1 - 1M memfd
~~~~~~~~~~~~~~~~~~~~~~

This test case has two memfds with 1M memory each in 4k pages, plus other preservations from LUO core and other KHO users.

This is how the radix tree stats look like:

    radix_nodes:       0x2f
    nr_preservations:  0x22d
    mem_preserved:     0xa2b000
    per order preservations:
    order  0:  0x215
    order  1:  0x9
    order  2:  0x1
    order  3:  0x2
    order  4:  0x5
    order  5:  0x1
    order  6:  0x2
    order  7:  0x2
    order  9:  0x1
    order 10:  0x1

and this is how long it takes to extend the scratch after KHO boot:

kho_extend_scratch(): time taken: 88 us kho_extend_scratch(): total memory recovered: 0xf7ff7b000 (~62G)

Test case 2 - 1G memfd
~~~~~~~~~~~~~~~~~~~~~~

This test case has two memfds with 1G memory each in 4k pages, plus other preservations from LUO core and other KHO users.

This is how the radix tree stats look like:

    radix_nodes:       0x45
    nr_preservations:  0x80832
    mem_preserved:     0x8102d000
    per order preservations:
    order  0:  0x80817
    order  1:  0x7
    order  2:  0x2
    order  3:  0x4
    order  4:  0x2
    order  5:  0x2
    order  6:  0x4
    order  7:  0x3
    order  8:  0x1
    order  9:  0x2

and this is how long it takes to extend the scratch after KHO boot:

    kho_extend_scratch(): time taken: 21769 us
    kho_extend_scratch(): total memory recovered: 0xe40000000 (57G)
---
 include/linux/kexec_handover.h     |   1 +
 kernel/liveupdate/kexec_handover.c | 148 +++++++++++++++++++++++++----
 mm/mm_init.c                       |   1 +
 3 files changed, 133 insertions(+), 17 deletions(-)
include/linux/kexec_handover.h +1 -0
index 8968c56d2d73..6ce46f36ed99 100644
@@ -37,6 +37,7 @@ 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_extend_scratch(void);
 
 void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
 		  u64 scratch_len);
kernel/liveupdate/kexec_handover.c +131 -17

166 lines not on this page · raw message

mm/mm_init.c +1 -0
index eddc0f03a779..10916cdf0029 100644
@@ -2688,6 +2688,7 @@ void __init __weak mem_init(void)
 
 void __init mm_core_init_early(void)
 {
+	kho_extend_scratch();
 	hugetlb_cma_reserve();
 	hugetlb_bootmem_alloc();
 
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#48 lore raw

Re: [PATCH 10/12] kho: extended scratch

Quoted 30 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Methodology
===========

Introduce extended scratch areas. These areas are discovered at boot by walking the preserved memory radix tree and looking for free blocks of memory. They then marked as scratch to allow allocations from them. This makes KHO more resilient to memory pressure and allows supporting huge page preservation.

Since the preserved memory radix tree mixes both physical address and order into a single key, and does not track table pages, it is difficult to identify free areas from it directly. Walk the tree and digest it down into another radix tree. The latter tracks blocks of KHO_EXT_SHIFT (1 GiB as of now) granularity. Then walk the digested tree and mark the areas between the present keys as scratch.

---
 include/linux/kexec_handover.h     |   1 +
 kernel/liveupdate/kexec_handover.c | 148 +++++++++++++++++++++++++----
 mm/mm_init.c                       |   1 +
 3 files changed, 133 insertions(+), 17 deletions(-)
kernel/liveupdate/kexec_handover.c +0 -0
index 1a04e089f779..c2b843a5fb28 100644

kernel/liveupdate/kexec_handover.c static void __init kho_reserve_scratch(void) · line 860

Quoted 4 lines
kernel/liveupdate/kexec_handover.c +1 -0
@@ -840,6 +857,120 @@ static void __init kho_reserve_scratch(void)
 	kho_enable = false;
 }
 
+#define KHO_EXT_SHIFT 30 /* 1 GiB */

arm64 does not necessarily use 1G gigantic pages and worse, it can have 2 gigantic hstates.

I think this should take into account what actual gigantic page sizes are in use for the general case.

Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#49 lore raw

Re: [PATCH 10/12] kho: extended scratch

Quoted 34 lines · Mike Rapoport
Quoted 33 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Methodology
===========

Introduce extended scratch areas. These areas are discovered at boot by walking the preserved memory radix tree and looking for free blocks of memory. They then marked as scratch to allow allocations from them. This makes KHO more resilient to memory pressure and allows supporting huge page preservation.

Since the preserved memory radix tree mixes both physical address and order into a single key, and does not track table pages, it is difficult to identify free areas from it directly. Walk the tree and digest it down into another radix tree. The latter tracks blocks of KHO_EXT_SHIFT (1 GiB as of now) granularity. Then walk the digested tree and mark the areas between the present keys as scratch.

---
 include/linux/kexec_handover.h     |   1 +
 kernel/liveupdate/kexec_handover.c | 148 +++++++++++++++++++++++++----
 mm/mm_init.c                       |   1 +
 3 files changed, 133 insertions(+), 17 deletions(-)
kernel/liveupdate/kexec_handover.c +0 -0
index 1a04e089f779..c2b843a5fb28 100644
@@ -840,6 +857,120 @@ static void __init kho_reserve_scratch(void)
 	kho_enable = false;
 }
 
Quoted 7 lines

kernel/liveupdate/kexec_handover.c static void __init kho_reserve_scratch(void) · line 860

Quoted 1 line
kernel/liveupdate/kexec_handover.c +1 -0
+#define KHO_EXT_SHIFT 30 /* 1 GiB */

arm64 does not necessarily use 1G gigantic pages and worse, it can have 2 gigantic hstates.

I think this should take into account what actual gigantic page sizes are in use for the general case.

This has nothing to with the gigantic page sizes. This is simply the granularity at which KHO looks for free blocks. Making this larger means less memory usage and better performance at the cost of amount of memory recovered. Making this smaller does the opposite.

I picked 1G because it "feels" the right balance. Mostly gut feeling without real science behind the number. I can make it smaller or larger if you'd like.

Signature · 2 lines
Regards,
Pratyush Yadav
author maintainer
#50 lore raw

PATCH 11/12 kho: return virtual address of mem_map

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

There are currently 3 callers of kho_get_mem_map_phys(). Two of them, kho_mem_retrieve() and kho_extend_scratch() need the virtual address. The third, kho_populate() doesn't care. Make things simpler by directly returning the virtual address. Rename kho_get_mem_map_phys() to kho_get_mem_map() to accurately reflect what it returns.

---
 kernel/liveupdate/kexec_handover.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
kernel/liveupdate/kexec_handover.c +15 -13
index c2b843a5fb28..2e13b80d1c7d 100644
@@ -625,10 +625,11 @@ static int __init kho_preserved_memory_reserve(unsigned long key, void *data)
 	return 0;
 }
 
-/* Returns physical address of the preserved memory map from FDT */
-static phys_addr_t __init kho_get_mem_map_phys(const void *fdt)
+/* Returns virtual address of the preserved memory map from FDT */
+static __init void *kho_get_mem_map(const void *fdt)
 {
 	const void *mem_ptr;
+	phys_addr_t mem_map_phys;
 	int len;
 
 	mem_ptr = fdt_getprop(fdt, 0, KHO_FDT_MEMORY_MAP_PROP_NAME, &len);
@@ -637,7 +638,11 @@ static phys_addr_t __init kho_get_mem_map_phys(const void *fdt)
 		return 0;
 	}
 
-	return get_unaligned((const u64 *)mem_ptr);
+	mem_map_phys = get_unaligned((const u64 *)mem_ptr);
+	if (!mem_map_phys)
+		return NULL;
+
+	return phys_to_virt(mem_map_phys);
 }
 
 /*
@@ -932,15 +937,15 @@ void __init kho_extend_scratch(void)
 		.key = kho_ext_mark_scratch,
 	};
 	struct kho_radix_tree radix;
-	phys_addr_t prev_end = 0, mem_map_phys;
+	phys_addr_t prev_end = 0;
 	int err = 0;
 
 	if (!is_kho_boot())
 		return;
 
 	/* Make sure the KHO radix tree is initialized. */
-	mem_map_phys = kho_get_mem_map_phys(kho_get_fdt());
-	err = kho_radix_init_tree(&kho_in.radix_tree, phys_to_virt(mem_map_phys));
+	err = kho_radix_init_tree(&kho_in.radix_tree,
+				  kho_get_mem_map(kho_get_fdt()));
 	if (err)
 		goto print;
 
@@ -1587,11 +1592,9 @@ static int __init kho_mem_retrieve(const void *fdt)
 	const struct kho_radix_walk_cb cb = {
 		.key = kho_preserved_memory_reserve,
 	};
-	phys_addr_t mem_map_phys;
 	int err;
 
-	mem_map_phys = kho_get_mem_map_phys(fdt);
-	err = kho_radix_init_tree(&kho_in.radix_tree, phys_to_virt(mem_map_phys));
+	err = kho_radix_init_tree(&kho_in.radix_tree, kho_get_mem_map(fdt));
 	if (err)
 		return err;
 
@@ -1816,8 +1819,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
 {
 	unsigned int scratch_cnt = scratch_len / sizeof(*kho_scratch);
 	struct kho_scratch *scratch = NULL;
-	phys_addr_t mem_map_phys;
-	void *fdt = NULL;
+	void *fdt = NULL, *mem_map;
 	bool populated = false;
 	int err;
 
@@ -1840,8 +1842,8 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
 		goto unmap_fdt;
 	}
 
-	mem_map_phys = kho_get_mem_map_phys(fdt);
-	if (!mem_map_phys)
+	mem_map = kho_get_mem_map(fdt);
+	if (!mem_map)
 		goto unmap_fdt;
 
 	scratch = early_memremap(scratch_phys, scratch_len);
Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#51 lore raw

Re: [PATCH 11/12] kho: return virtual address of mem_map

Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

There are currently 3 callers of kho_get_mem_map_phys(). Two of them, kho_mem_retrieve() and kho_extend_scratch() need the virtual address. The third, kho_populate() doesn't care. Make things simpler by directly returning the virtual address. Rename kho_get_mem_map_phys() to kho_get_mem_map() to accurately reflect what it returns.

This should be moved earlier, before replacing open-coded get_mem_map() with a call to kho_get_mem_map_phys().

Quoted 4 lines
---
 kernel/liveupdate/kexec_handover.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#52 lore raw

Re: [PATCH 11/12] kho: return virtual address of mem_map

Quoted 11 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

There are currently 3 callers of kho_get_mem_map_phys(). Two of them, kho_mem_retrieve() and kho_extend_scratch() need the virtual address. The third, kho_populate() doesn't care. Make things simpler by directly returning the virtual address. Rename kho_get_mem_map_phys() to kho_get_mem_map() to accurately reflect what it returns.

This should be moved earlier, before replacing open-coded get_mem_map() with a call to kho_get_mem_map_phys().

Do you mean move it before patch 2 "kho: store incoming radix tree in kho_in"?

I can do that. I did it this way to show a clear need for this function, but I don't mind doing it as a preparatory step.

Quoted 5 lines
Quoted 5 lines
---
 kernel/liveupdate/kexec_handover.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#53 lore raw

Re: [PATCH 11/12] kho: return virtual address of mem_map

Quoted 11 lines · Pratyush Yadav
Quoted 9 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

There are currently 3 callers of kho_get_mem_map_phys(). Two of them, kho_mem_retrieve() and kho_extend_scratch() need the virtual address. The third, kho_populate() doesn't care. Make things simpler by directly returning the virtual address. Rename kho_get_mem_map_phys() to kho_get_mem_map() to accurately reflect what it returns.

Quoted 5 lines
Quoted 2 lines

This should be moved earlier, before replacing open-coded get_mem_map() with a call to kho_get_mem_map_phys().

Do you mean move it before patch 2 "kho: store incoming radix tree in kho_in"?

Yes.

Quoted 2 lines

I can do that. I did it this way to show a clear need for this function, but I don't mind doing it as a preparatory step.

With the usual "it will be used in the upcoming changes" text in the log it's fine :)

Quoted 9 lines
Quoted 5 lines
Quoted 5 lines
---
 kernel/liveupdate/kexec_handover.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#54 lore raw

PATCH 12/12 mm/hugetlb: make bootmem allocation work with KHO

In reply to Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Gigantic page allocation is somewhat broken currently when KHO is used.

Firstly, they break KHO scratch size accounting. RSRV_KERN is used to track how much memory is reserved for use by the kernel. Since alloc_bootmem() calls the memblock_alloc*() APIs, the hugepages allocated also get marked as RSRV_KERN.

Allocations marked RSRV_KERN are used by KHO to calculate how much scratch space it should reserve to make sure the next kernel has enough memory to boot when it is in scratch-only phase. Counting hugepages in that blows up scratch size, and can lead to the scratch allocation failing, making KHO unusable. This will show up when huge pages make up more than 50% of the system, which is a fairly common use case.

Secondly, while not supported right now, huge pages are user memory and can be preserved via KHO. The scratch spaces should not have any preserved memory. Allocating hugepages from scratch (on a KHO boot) can lead to them being un-preservable.

Introduce memblock_alloc_nid_user(). This does two things: first, it instructs __memblock_alloc_range_nid() to not use scratch areas to fulfill allocation. If KHO is in scratch-only mode, allocations will only be made from extended scratch areas. Second, it removes RSRV_KERN from the allocation to make sure it doesn't mess up scratch size accounting.

To reduce duplication, introduce __memblock_alloc_range_nid() which does exactly what memblock_alloc_range_nid() used to do, but takes the flags from its caller. Then make memblock_alloc_range_nid() a wrapper to it. This lets memblock_alloc_nid_user() re-use most of the logic without causing churn to update all callers of memblock_alloc_range_nid() and adding yet another argument to it.

---

Notes:
Checkpatch complains here about the alignment of arguments of memblock_alloc_range_nid() with open parentheses. That can be ignored since the code already was mis-aligned, and for good reason.

 include/linux/memblock.h |   4 ++
 mm/hugetlb.c             |  19 ++----
 mm/memblock.c            | 138 ++++++++++++++++++++++++++++++---------
 3 files changed, 116 insertions(+), 45 deletions(-)
include/linux/memblock.h +4 -0
index 4f535ca4947a..c7056cf3f0f2 100644
@@ -160,6 +160,7 @@ int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
 int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
 int memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t size);
 int memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size);
+int memblock_reserved_clear_kern(phys_addr_t base, phys_addr_t size);
 int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size);
 int memblock_mark_kho_scratch_ext(phys_addr_t base, phys_addr_t size);
 int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size);
@@ -431,6 +432,9 @@ 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_nid_user(phys_addr_t size, phys_addr_t align, int nid,
+			      bool exact_nid);
+
 static __always_inline void *memblock_alloc(phys_addr_t size, phys_addr_t align)
 {
 	return memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT,
mm/hugetlb.c +6 -13
index f24bf49be047..5ba393b0a581 100644
@@ -3049,26 +3049,19 @@ static __init void *alloc_bootmem(struct hstate *h, int nid, bool node_exact)
 	if (hugetlb_early_cma(h))
 		m = hugetlb_cma_alloc_bootmem(h, &listnode, node_exact);
 	else {
-		if (node_exact)
-			m = memblock_alloc_exact_nid_raw(huge_page_size(h),
-				huge_page_size(h), 0,
-				MEMBLOCK_ALLOC_ACCESSIBLE, nid);
-		else {
-			m = memblock_alloc_try_nid_raw(huge_page_size(h),
-				huge_page_size(h), 0,
-				MEMBLOCK_ALLOC_ACCESSIBLE, nid);
+		m = memblock_alloc_nid_user(huge_page_size(h), huge_page_size(h),
+					    nid, node_exact);
+		if (m) {
 			/*
 			 * For pre-HVO to work correctly, pages need to be on
 			 * the list for the node they were actually allocated
 			 * from. That node may be different in the case of
-			 * fallback by memblock_alloc_try_nid_raw. So,
-			 * extract the actual node first.
+			 * fallback by memblock_alloc_try_nid_raw. So, extract
+			 * the actual node first.
 			 */
-			if (m)
+			if (node_exact)
 				listnode = early_pfn_to_nid(PHYS_PFN(__pa(m)));
-		}
 
-		if (m) {
 			m->flags = 0;
 			m->cma = NULL;
 		}
mm/memblock.c +106 -32

179 lines not on this page · raw message

Signature · 1 line
2.54.0.545.g6539524ca2-goog
maintainer
#55 lore raw

Re: [PATCH 12/12] mm/hugetlb: make bootmem allocation work with KHO

Hi Pratyush,

Quoted 8 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Gigantic page allocation is somewhat broken currently when KHO is used.

Firstly, they break KHO scratch size accounting. RSRV_KERN is used to track how much memory is reserved for use by the kernel. Since alloc_bootmem() calls the memblock_alloc*() APIs, the hugepages allocated also get marked as RSRV_KERN.

The intended semantics of RSRV_KERN was to distinguish memory reserved because it's in use by firmware from the memory reserved or allocated by the kernel. It does not have to be directly used by the kernel, some of PG_Reserved memory is mapped to user-space and it's not only hugetlb. There are zero pages, VDSO and maybe something else, I don't remember.

Quoted 3 lines

Allocations marked RSRV_KERN are used by KHO to calculate how much scratch space it should reserve to make sure the next kernel has enough memory to boot when it is in scratch-only phase. Counting hugepages in

The size of RSRV_KERN allocations is also used in memblock_estimated_nr_free_pages() that's currently used by set_max_threads() to set several rlimits and by s390 to allocate colored zero pages. Excluding hugetlb from that will skew the calculations there.

Quoted 16 lines

that blows up scratch size, and can lead to the scratch allocation failing, making KHO unusable. This will show up when huge pages make up more than 50% of the system, which is a fairly common use case.

Secondly, while not supported right now, huge pages are user memory and can be preserved via KHO. The scratch spaces should not have any preserved memory. Allocating hugepages from scratch (on a KHO boot) can lead to them being un-preservable.

Introduce memblock_alloc_nid_user(). This does two things: first, it instructs __memblock_alloc_range_nid() to not use scratch areas to fulfill allocation. If KHO is in scratch-only mode, allocations will only be made from extended scratch areas. Second, it removes RSRV_KERN from the allocation to make sure it doesn't mess up scratch size accounting.

Quoted 6 lines

To reduce duplication, introduce __memblock_alloc_range_nid() which does exactly what memblock_alloc_range_nid() used to do, but takes the flags from its caller. Then make memblock_alloc_range_nid() a wrapper to it. This lets memblock_alloc_nid_user() re-use most of the logic without causing churn to update all callers of memblock_alloc_range_nid() and adding yet another argument to it.

That's neat :)

But I'm not too fond of the memblock_alloc_nid_user() as a concept. That early at boot everything is still kernel, even though hugetlb pages might become user afterwards if they are actually consumed.
Another thing, is that adding such global API to memblock could be abused and suddenly some early code will clear RSRV_KERN for a random pieces of memory.

If we'd still need a special memblock function for gigantic pages allocation I'd rather make it explicit that it's for hugetlb and keep it in mm/internal.h

I was thinking about possible alternative solutions and here's what I came up with

1. SCRATCH_EXT nicely increases the memory pool available to memblock, but the decision which memory can be used for which allocations becomes more complex. It should make sure that SCRATCH is not used for hugetlb, but OTOH it's preferred for other early allocations. With implicit interaction between choose_memblock_flags() and should_skip_region() this seems to me quite a headache. memblock_reserved_clear_kern() should be changed to something else to keep set_max_threads() working. And, IMHO, memblock_alloc_nid_user() should be turned into memblock_alloc_gigantic_hugetlb() and only exposed to MM code. It's even possible that it will duplicate some of memblock_alloc_range_nid) rather than use it because hugetlb is always a special case.

2. Split memblock_reserve() part from kho_mem_retrieve() to run before hugetlb allocations. With this we won't need new types and APIs, we can ensure that hugetlb allocations do not use SCRATCH by reserving scratch areas before hugetlb allocations and releasing them afterwards. Obviously this is the slowest option as it will slow down all memblock allocations from the point we memblock_reserve() preserved memory. Still realistically I wouldn't expect large impact on performance because the heaviest part there is reserving of the preserved memory that has to happen anyway. Also, I don't thing that a system that uses a lot of gigantic pages will have a lot of preserved chunks scattered around.

3. Move the complexity into hugetlb and make it preserve all the gigantic pages with KHO. This means, though, that we won't be able to increase the number of gigantic pages after the first boot (although decreasing it seems easy) and that we need to let scratch auto scaling understand what were the "normal" memblock allocations and what were the allocations of the gigantic pages.

4. Invert SCRATCH_EXT logic and instead of freeing large chunks around the preserved memory to SCRATCH_EXT, reserve memory surrounding the preserved areas and release scratch_only before hugetlb allocations. We'd still need to somehow prevent hugetlb allocation spilling into scratch and there's a nasty piece of releasing the memory around the preserved chunks. On the bright side, I think it's feasible to defer the release of those regions and free them when we are already multithreaded. This probably the most involved alternative but it also could help with the bottleneck of kho_mem_retrieve() creating too many memblock.reserved regions.

Thoughts?

Quoted 12 lines

---

Notes:
Checkpatch complains here about the alignment of arguments of memblock_alloc_range_nid() with open parentheses. That can be ignored since the code already was mis-aligned, and for good reason.

 include/linux/memblock.h |   4 ++
 mm/hugetlb.c             |  19 ++----
 mm/memblock.c            | 138 ++++++++++++++++++++++++++++++---------
 3 files changed, 116 insertions(+), 45 deletions(-)
Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#56 lore raw

Re: [PATCH 12/12] mm/hugetlb: make bootmem allocation work with KHO

Hi Mike,

Quoted 18 lines · Mike Rapoport

Hi Pratyush,

Quoted 8 lines · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Gigantic page allocation is somewhat broken currently when KHO is used.

Firstly, they break KHO scratch size accounting. RSRV_KERN is used to track how much memory is reserved for use by the kernel. Since alloc_bootmem() calls the memblock_alloc*() APIs, the hugepages allocated also get marked as RSRV_KERN.

The intended semantics of RSRV_KERN was to distinguish memory reserved because it's in use by firmware from the memory reserved or allocated by the kernel. It does not have to be directly used by the kernel, some of PG_Reserved memory is mapped to user-space and it's not only hugetlb. There are zero pages, VDSO and maybe something else, I don't remember.

Quoted 8 lines
Quoted 3 lines

Allocations marked RSRV_KERN are used by KHO to calculate how much scratch space it should reserve to make sure the next kernel has enough memory to boot when it is in scratch-only phase. Counting hugepages in

The size of RSRV_KERN allocations is also used in memblock_estimated_nr_free_pages() that's currently used by set_max_threads() to set several rlimits and by s390 to allocate colored zero pages. Excluding hugetlb from that will skew the calculations there.

Oh, I didn't know that. I thought it was only for KHO.

Quoted 33 lines
Quoted 17 lines

that blows up scratch size, and can lead to the scratch allocation failing, making KHO unusable. This will show up when huge pages make up more than 50% of the system, which is a fairly common use case.

Secondly, while not supported right now, huge pages are user memory and can be preserved via KHO. The scratch spaces should not have any preserved memory. Allocating hugepages from scratch (on a KHO boot) can lead to them being un-preservable.

Introduce memblock_alloc_nid_user(). This does two things: first, it instructs __memblock_alloc_range_nid() to not use scratch areas to fulfill allocation. If KHO is in scratch-only mode, allocations will only be made from extended scratch areas. Second, it removes RSRV_KERN from the allocation to make sure it doesn't mess up scratch size accounting.

Quoted 6 lines

To reduce duplication, introduce __memblock_alloc_range_nid() which does exactly what memblock_alloc_range_nid() used to do, but takes the flags from its caller. Then make memblock_alloc_range_nid() a wrapper to it. This lets memblock_alloc_nid_user() re-use most of the logic without causing churn to update all callers of memblock_alloc_range_nid() and adding yet another argument to it.

That's neat :)

But I'm not too fond of the memblock_alloc_nid_user() as a concept. That early at boot everything is still kernel, even though hugetlb pages might become user afterwards if they are actually consumed.
Another thing, is that adding such global API to memblock could be abused and suddenly some early code will clear RSRV_KERN for a random pieces of memory.

Quoted 3 lines

If we'd still need a special memblock function for gigantic pages allocation I'd rather make it explicit that it's for hugetlb and keep it in mm/internal.h

Sure, that would work I think.

Quoted 3 lines

I was thinking about possible alternative solutions and here's what I came up with

Thanks for the ideas, much appreciated!

Quoted 7 lines

1. SCRATCH_EXT nicely increases the memory pool available to memblock, but the decision which memory can be used for which allocations becomes more complex. It should make sure that SCRATCH is not used for hugetlb, but OTOH it's preferred for other early allocations. With implicit interaction between choose_memblock_flags() and should_skip_region() this seems to me quite a headache.

Yep, I agree. I can try to refactor some of the logic to make this easier to understand, but I am not sure how successful I would be.

Quoted 6 lines

memblock_reserved_clear_kern() should be changed to something else to keep set_max_threads() working. And, IMHO, memblock_alloc_nid_user() should be turned into memblock_alloc_gigantic_hugetlb() and only exposed to MM code. It's even possible that it will duplicate some of memblock_alloc_range_nid) rather than use it because hugetlb is always a special case.

That's fine by me I think. Perhaps we can also hide the complexity of the allocation strategy here? For example, we won't have to expose the semantic of SCRATCH_EXT only allocations to the rest of the memblock allocation machinery.

Quoted 11 lines

2. Split memblock_reserve() part from kho_mem_retrieve() to run before hugetlb allocations. With this we won't need new types and APIs, we can ensure that hugetlb allocations do not use SCRATCH by reserving scratch areas before hugetlb allocations and releasing them afterwards. Obviously this is the slowest option as it will slow down all memblock allocations from the point we memblock_reserve() preserved memory. Still realistically I wouldn't expect large impact on performance because the heaviest part there is reserving of the preserved memory that has to happen anyway. Also, I don't thing that a system that uses a lot of gigantic pages will have a lot of preserved chunks scattered around.

This option would make my life easier (in the short term) because I think it is the easiest to implement. But I don't think this is good for KHO long term.

First, I think the memblock_reserve() calls are band-aid and we should get rid of them entirely. They scale terribly. With even a few gigabytes of memory they go in the order of seconds. I ran a quick experiment, and with around 4 GiB of 4k preservations, it takes around 650 ms on my test machine.

And this isn't a theoretical use case. We are looking to preserve similar sized memfds on our machines. This would be on top of having a few terabytes in 1G huge pages. I think we should integrate KHO more deeply into the memblock -> buddy handover sequence.

Second, while you pay the same cost on doing the memblock_reserve(), the reservations need to happen much sooner. Right now, the reservations happen right before memblock_free_all(). With this we would need to move the reservations to mm_core_init_early() which happens right after setup_arch(). So every allocation after mm_core_init_early() will take a hit. While I haven't measured the performance impact with this, I imagine it won't be trivial.

Quoted 7 lines

3. Move the complexity into hugetlb and make it preserve all the gigantic pages with KHO. This means, though, that we won't be able to increase the number of gigantic pages after the first boot (although decreasing it seems easy) and that we need to let scratch auto scaling understand what were the "normal" memblock allocations and what were the allocations of the gigantic pages.

This is a viable option. There is of course the limitation of not being able to add more gigantic pages but I suppose most workloads should be able to live with that. The obvious downside is that you don't have a fallback if scratch runs out so KHO will be a little less resilient.

The complexity with this comes with correctly preserving all the gigantic pages. Hugepages can be removed at runtime, so we would need to plug into the removal mechanism. There's also demotion and other things that need to be taken care of. The reason we need to track this is because what if the freed hugepage now contains preserved memory from something else.

Quoted 11 lines

4. Invert SCRATCH_EXT logic and instead of freeing large chunks around the preserved memory to SCRATCH_EXT, reserve memory surrounding the preserved areas and release scratch_only before hugetlb allocations. We'd still need to somehow prevent hugetlb allocation spilling into scratch and there's a nasty piece of releasing the memory around the preserved chunks. On the bright side, I think it's feasible to defer the release of those regions and free them when we are already multithreaded. This probably the most involved alternative but it also could help with the bottleneck of kho_mem_retrieve() creating too many memblock.reserved regions.

I think we should fix kho_mem_retrieve() by making memblock_free_all() and deferred_free_pages() aware of KHO. I feel that splitting the freeing of pages into two phases is going to make the early boot more complicated than it needs to. And on top of all this we still need to do the special case thing for hugetlb anyway. So I am not sure if this is a good idea...

Quoted 2 lines

Thoughts?

I personally like option 1 the most (maybe because it is very similar to my patchset). My point is, if you think the "extended scratch" is fine as a concept and we only need to clean up the neighbouring stuff like memblock allocation strategy, then I would like to pursue this since I think this has the most potential.

I think option 3 is also viable. While I personally am not a huge fan, I don't have it either. So if you really dislike 1 then I can try to make 3 work.

Option 4 can kind of work, but it just gives me a bad feeling that it will make early boot memory management more complex and might result in flaky boot failures.

Option 2 is the worst of the lot I think. It is the easiest to implement, but I think it just adds to the tech debt that memblock_reserve() is.

So, in summary, I would like to pursue option 1 and try to make it more appetizing. But I would like to at least know if you hate the "extended scratch" (ignore the name) as a concept or only the code it results in.

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#57 lore raw

Re: [PATCH 12/12] mm/hugetlb: make bootmem allocation work with KHO

Quoted 7 lines · Pratyush Yadav
Quoted 2 lines · Mike Rapoport
Quoted 1 line · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

So, in summary, I would like to pursue option 1 and try to make it more appetizing. But I would like to at least know if you hate the "extended scratch" (ignore the name) as a concept or only the code it results in.

Let's retry this one :)

I looked more closely, and it seems that mixing SCRATCH and SCRATCH_EXT should be a lesser headache than going with option 4.

Tracking the changes in gigantic pages in hugetlb also does not seem something we'd like to pursue especially considering that memory from freed or demoted gigantic pages could be reserved.

If we add a dedicated memblock_something to allocate gigantic pages, we can reduce branching in alloc_bootmem() to

	if (cma)
		do_cma()
	else
		do_memblock()

For hugetlb_cma we might want to teach CMA to create pre-allocated areas and then it could reuse the same memblock API. This seems useful even regardless of KHO.

Signature · 2 lines
Sincerely yours,
Mike.
author maintainer
#58 lore raw

Re: [PATCH 12/12] mm/hugetlb: make bootmem allocation work with KHO

Quoted 5 lines · Mike Rapoport
Quoted 4 lines · Pratyush Yadav
Quoted 2 lines · Mike Rapoport
Quoted 1 line · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

Quoted 8 lines
Quoted 3 lines

So, in summary, I would like to pursue option 1 and try to make it more appetizing. But I would like to at least know if you hate the "extended scratch" (ignore the name) as a concept or only the code it results in.

Let's retry this one :)

I looked more closely, and it seems that mixing SCRATCH and SCRATCH_EXT should be a lesser headache than going with option 4.

I also had some time to ruminate on this. I still think option 1 has the most promise, but my opinion on option 4 has improved a bit. While I still am not sure adding a 3rd phase to struct page/MM init (early -> deferred -> KHO reserved blocks) is a good idea, I think it might not be as bad as I first thought. Dunno...

Anyway, for now I think I will try to make option 1 more appetizing.

Here's an idea I want to try out: I get rid of SCRATCH_EXT and mark the free blocks as SCRATCH. For HugeTLB, I can teach the special memblock_alloc_hugetlb_something() function to exclude scratch areas when looking for free memory ranges. So core memblock does not get a new memory type, and the complexity of hugepage allocation does not leak into memblock.

How does that sound?

Quoted 8 lines

Tracking the changes in gigantic pages in hugetlb also does not seem something we'd like to pursue especially considering that memory from freed or demoted gigantic pages could be reserved.

If we add a dedicated memblock_something to allocate gigantic pages, we can reduce branching in alloc_bootmem() to

Quoted 8 lines
	if (cma)
		do_cma()
	else
		do_memblock()

For hugetlb_cma we might want to teach CMA to create pre-allocated areas and then it could reuse the same memblock API. This seems useful even regardless of KHO.

Sorry, I don't get what you mean by this. What pre-allocated areas? When creating CMA areas it calls cma_alloc_mem() which calls into memblock. What would we change about this?

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#59 lore raw

Re: [PATCH 12/12] mm/hugetlb: make bootmem allocation work with KHO

Quoted 13 lines · Pratyush Yadav
Quoted 11 lines · Mike Rapoport
Quoted 7 lines · Pratyush Yadav
Quoted 2 lines · Mike Rapoport
Quoted 1 line · Pratyush Yadav

From: "Pratyush Yadav (Google)" <[email protected]>

So, in summary, I would like to pursue option 1 and try to make it more appetizing. But I would like to at least know if you hate the "extended scratch" (ignore the name) as a concept or only the code it results in.

Let's retry this one :)

Quoted 8 lines
Quoted 2 lines

I looked more closely, and it seems that mixing SCRATCH and SCRATCH_EXT should be a lesser headache than going with option 4.

I also had some time to ruminate on this. I still think option 1 has the most promise, but my opinion on option 4 has improved a bit. While I still am not sure adding a 3rd phase to struct page/MM init (early -> deferred -> KHO reserved blocks) is a good idea, I think it might not be as bad as I first thought. Dunno...

Until (if ever) we enlighten memblock_free_all()/deferred_init_pages() about KHO, small scattered reservation make memblock slower. It's hard to tell if delaying more complex initialization of the large reserved chunks until SMP is worth speedup in a few memblock operations between kho_memory_init() and the end of deferred_init_pages().

Quoted 10 lines

Anyway, for now I think I will try to make option 1 more appetizing.

Here's an idea I want to try out: I get rid of SCRATCH_EXT and mark the free blocks as SCRATCH. For HugeTLB, I can teach the special memblock_alloc_hugetlb_something() function to exclude scratch areas when looking for free memory ranges. So core memblock does not get a new memory type, and the complexity of hugepage allocation does not leak into memblock.

How does that sound?

It sounds fine, let's see how it looks :)

Quoted 12 lines
Quoted 12 lines

Tracking the changes in gigantic pages in hugetlb also does not seem something we'd like to pursue especially considering that memory from freed or demoted gigantic pages could be reserved.

If we add a dedicated memblock_something to allocate gigantic pages, we can reduce branching in alloc_bootmem() to

	if (cma)
		do_cma()
	else
		do_memblock()
Quoted 7 lines
Quoted 3 lines

For hugetlb_cma we might want to teach CMA to create pre-allocated areas and then it could reuse the same memblock API. This seems useful even regardless of KHO.

Sorry, I don't get what you mean by this. What pre-allocated areas? When creating CMA areas it calls cma_alloc_mem() which calls into memblock. What would we change about this?

s/teach CMA to create/teach CMA to use/

I mean that we might want to be able first allocate gigantic pages and then feed them to empty CMA areas.

Quoted 3 lines
Signature · 2 lines
Regards,
Pratyush Yadav
Signature · 2 lines
Sincerely yours,
Mike.