WIP: Convert KHO bitmap serialization to KHO array
Signed-off-by: Pratyush Yadav <pratyush@kernel.org>
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 05f5694e..ce8cc38 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/page-isolation.h>
+#include <linux/kho_array.h>
#include <asm/early_ioremap.h>
@@ -96,8 +97,8 @@ struct kho_out {
struct mutex fdts_lock;
struct kho_mem_track track;
- /* First chunk of serialized preserved memory map */
- struct khoser_mem_chunk *preserved_mem_map;
+ /* Serialized preserved memory map */
+ struct kho_array *preserved_mem_map;
struct kho_debugfs dbg;
};
@@ -255,11 +256,11 @@ EXPORT_SYMBOL_GPL(kho_restore_folio);
/* Serialize and deserialize struct kho_mem_phys across kexec
*
- * Record all the bitmaps in a linked list of pages for the next kernel to
- * process. Each chunk holds bitmaps of the same order and each block of bitmaps
- * starts at a given physical address. This allows the bitmaps to be sparse. The
- * xarray is used to store them in a tree while building up the data structure,
- * but the KHO successor kernel only needs to process them once in order.
+ * Record all the bitmaps in a KHO array for the next kernel to process. Each
+ * bitmap stores the order of the folios and starts at a given physical address.
+ * This allows the bitmaps to be sparse. The xarray is used to store them in a
+ * tree while building up the data structure, but the KHO successor kernel only
+ * needs to process them once in order.
*
* All of this memory is normal kmalloc() memory and is not marked for
* preservation. The successor kernel will remain isolated to the scratch space
@@ -269,118 +270,107 @@ EXPORT_SYMBOL_GPL(kho_restore_folio);
struct khoser_mem_bitmap_ptr {
phys_addr_t phys_start;
+ unsigned int order;
+ unsigned int __reserved;
DECLARE_KHOSER_PTR(bitmap, struct kho_mem_phys_bits *);
};
-struct khoser_mem_chunk_hdr {
- DECLARE_KHOSER_PTR(next, struct khoser_mem_chunk *);
- unsigned int order;
- unsigned int num_elms;
-};
-
-#define KHOSER_BITMAP_SIZE \
- ((PAGE_SIZE - sizeof(struct khoser_mem_chunk_hdr)) / \
- sizeof(struct khoser_mem_bitmap_ptr))
-
-struct khoser_mem_chunk {
- struct khoser_mem_chunk_hdr hdr;
- struct khoser_mem_bitmap_ptr bitmaps[KHOSER_BITMAP_SIZE];
-};
-
-static_assert(sizeof(struct khoser_mem_chunk) == PAGE_SIZE);
-
-static struct khoser_mem_chunk *new_chunk(struct khoser_mem_chunk *cur_chunk,
- unsigned long order)
+static struct khoser_mem_bitmap_ptr *new_bitmap(phys_addr_t start,
+ struct kho_mem_phys_bits *bits,
+ unsigned int order)
{
- struct khoser_mem_chunk *chunk;
+ struct khoser_mem_bitmap_ptr *bitmap;
- chunk = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!chunk)
+ bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
+ if (!bitmap)
return NULL;
- chunk->hdr.order = order;
- if (cur_chunk)
- KHOSER_STORE_PTR(cur_chunk->hdr.next, chunk);
- return chunk;
+
+ bitmap->phys_start = start;
+ bitmap->order = order;
+ KHOSER_STORE_PTR(bitmap->bitmap, bits);
+ return bitmap;
}
-static void kho_mem_ser_free(struct khoser_mem_chunk *first_chunk)
+static void kho_mem_ser_free(struct kho_array *ka)
{
- struct khoser_mem_chunk *chunk = first_chunk;
+ struct khoser_mem_bitmap_ptr *elm;
+ struct ka_iter iter;
- while (chunk) {
- struct khoser_mem_chunk *tmp = chunk;
+ if (!ka)
+ return;
- chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
- kfree(tmp);
- }
+ ka_iter_init_read(&iter, ka);
+ ka_iter_for_each(&iter, elm)
+ kfree(elm);
+
+ kho_array_destroy(ka);
+ kfree(ka);
}
static int kho_mem_serialize(struct kho_out *kho_out)
{
- struct khoser_mem_chunk *first_chunk = NULL;
- struct khoser_mem_chunk *chunk = NULL;
struct kho_mem_phys *physxa;
- unsigned long order;
+ unsigned long order, pos = 0;
+ struct kho_array *ka = NULL;
+ struct ka_iter iter;
+
+ ka = kzalloc(sizeof(*ka), GFP_KERNEL);
+ if (!ka)
+ return -ENOMEM;
+ ka_iter_init_write(&iter, ka);
xa_for_each(&kho_out->track.orders, order, physxa) {
struct kho_mem_phys_bits *bits;
unsigned long phys;
- chunk = new_chunk(chunk, order);
- if (!chunk)
- goto err_free;
-
- if (!first_chunk)
- first_chunk = chunk;
-
xa_for_each(&physxa->phys_bits, phys, bits) {
struct khoser_mem_bitmap_ptr *elm;
+ phys_addr_t start;
- if (chunk->hdr.num_elms == ARRAY_SIZE(chunk->bitmaps)) {
- chunk = new_chunk(chunk, order);
- if (!chunk)
- goto err_free;
- }
+ start = (phys * PRESERVE_BITS) << (order + PAGE_SHIFT);
+ elm = new_bitmap(start, bits, order);
+ if (!elm)
+ goto err_free;
- elm = &chunk->bitmaps[chunk->hdr.num_elms];
- chunk->hdr.num_elms++;
- elm->phys_start = (phys * PRESERVE_BITS)
- << (order + PAGE_SHIFT);
- KHOSER_STORE_PTR(elm->bitmap, bits);
+ ka_iter_setpos(&iter, pos);
+ if (ka_iter_setentry(&iter, elm))
+ goto err_free;
+ pos++;
}
}
- kho_out->preserved_mem_map = first_chunk;
+ kho_out->preserved_mem_map = ka;
return 0;
err_free:
- kho_mem_ser_free(first_chunk);
+ kho_mem_ser_free(ka);
return -ENOMEM;
}
-static void __init deserialize_bitmap(unsigned int order,
- struct khoser_mem_bitmap_ptr *elm)
+static void __init deserialize_bitmap(struct khoser_mem_bitmap_ptr *elm)
{
struct kho_mem_phys_bits *bitmap = KHOSER_LOAD_PTR(elm->bitmap);
unsigned long bit;
for_each_set_bit(bit, bitmap->preserve, PRESERVE_BITS) {
- int sz = 1 << (order + PAGE_SHIFT);
+ int sz = 1 << (elm->order + PAGE_SHIFT);
phys_addr_t phys =
- elm->phys_start + (bit << (order + PAGE_SHIFT));
+ elm->phys_start + (bit << (elm->order + PAGE_SHIFT));
struct page *page = phys_to_page(phys);
memblock_reserve(phys, sz);
memblock_reserved_mark_noinit(phys, sz);
- page->private = order;
+ page->private = elm->order;
}
}
static void __init kho_mem_deserialize(const void *fdt)
{
- struct khoser_mem_chunk *chunk;
+ struct khoser_mem_bitmap_ptr *elm;
const phys_addr_t *mem;
+ struct kho_array *ka;
+ struct ka_iter iter;
int len;
mem = fdt_getprop(fdt, 0, PROP_PRESERVED_MEMORY_MAP, &len);
@@ -390,15 +380,17 @@ static void __init kho_mem_deserialize(const void *fdt)
return;
}
- chunk = *mem ? phys_to_virt(*mem) : NULL;
- while (chunk) {
- unsigned int i;
-
- for (i = 0; i != chunk->hdr.num_elms; i++)
- deserialize_bitmap(chunk->hdr.order,
- &chunk->bitmaps[i]);
- chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
+ ka = *mem ? phys_to_virt(*mem) : NULL;
+ if (!ka)
+ return;
+ if (!kho_array_valid(ka)) {
+ pr_err("invalid KHO array for preserved memory bitmaps\n");
+ return;
}
+
+ ka_iter_init_read(&iter, ka);
+ ka_iter_for_each(&iter, elm)
+ deserialize_bitmap(elm);
}
/*