All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pratyush Yadav <pratyush@kernel.org>
To: Mike Rapoport <rppt@kernel.org>
Cc: Pratyush Yadav <pratyush@kernel.org>,
	 Pasha Tatashin <pasha.tatashin@soleen.com>,
	 Alexander Graf <graf@amazon.com>,
	 Muchun Song <muchun.song@linux.dev>,
	 Oscar Salvador <osalvador@suse.de>,
	 David Hildenbrand <david@kernel.org>,
	 Andrew Morton <akpm@linux-foundation.org>,
	 Jason Miu <jasonmiu@google.com>,
	 Jork Loeser <jloeser@linux.microsoft.com>,
	 kexec@lists.infradead.org, linux-mm@kvack.org,
	 linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 18/21] kho: extend scratch
Date: Fri, 24 Jul 2026 18:54:03 +0200	[thread overview]
Message-ID: <2vxzjyqkgwgk.fsf@kernel.org> (raw)
In-Reply-To: <178410811939.820181.9175877917181976639.b4-review@b4> (Mike Rapoport's message of "Wed, 15 Jul 2026 12:35:19 +0300")

On Wed, Jul 15 2026, Mike Rapoport wrote:

>> 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
>> ===========
>> 
>> Discover areas that don't contain any preserved memory at boot by
>> walking the preserved memory radix tree. Mark them 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.
>> 
>> There is no inherent reason for using 1 GiB as the discovered block
>> size. This can be changed later if needed. Currently, KHO is mainly
>> targeted for server grade systems with hundreds of gigabytes to
>> terabytes of memory. So 1 GiB is a reasonable granularity for those
>> systems. For smaller systems this doesn't work as well, but we can
>> arrive at a better heuristic when we have concrete use cases.
>> 
>> 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:       0x13
>>     nr_preservations:  0x214
>>     mem_preserved:     0x227000
>> 
>>     per order preservations:
>>       order  0:  0x20f
>>       order  1:  0x4
>>       order  4:  0x1
>> 
>> and this is how long it takes to extend the scratch after KHO boot:
>> 
>>     KHO: KHO extend time: 47 us
>>     KHO: KHO extend total mem: 0xe6c17b000 (~57G)
>> 
>> 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:       0x28
>>     nr_preservations:  0x80816
>>     mem_preserved:     0x80829000
>> 
>>     per order preservations:
>>       order  0:  0x80811
>>       order  1:  0x4
>>       order  4:  0x1
>> 
>> and this is how long it takes to extend the scratch after KHO boot:
>> 
>>     KHO: KHO extend time: 22514 us
>>     KHO: KHO extend total mem: 0xd3f200000 (~52G)
>> 
>> Signed-off-by: Pratyush Yadav (Google) <pratyush@kernel.org>
>>
>> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
>> index b400976851e76..2c48488746290 100644
>> --- a/kernel/liveupdate/kexec_handover.c
>> +++ b/kernel/liveupdate/kexec_handover.c
>> @@ -84,6 +84,23 @@ static struct kho_out kho_out = {
>>  	},
>>  };
>>  
>> +struct kho_in {
>> +	phys_addr_t fdt_phys;
>> +	phys_addr_t scratch_phys;
>> +	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 = {
>> +};
>> +
>> +static const void *kho_get_fdt(void)
>> +{
>> +	return kho_in.fdt_phys ? phys_to_virt(kho_in.fdt_phys) : NULL;
>> +}
>> +
>>  /**
>>   * kho_encode_radix_key - Encodes a physical address and order into a radix key.
>>   * @phys: The physical address of the page.
>> @@ -895,6 +912,128 @@ static void __init kho_reserve_scratch(void)
>>  	kho_enable = false;
>>  }
>>  
>> +/*
>> + * Look for free blocks of 1G. This is a heuristic chosen to work efficiently
>> + * with large systems with hundreds of gigabytes of memory. It will work poorly
>> + * on smaller systems. The algorithm itself doesn't depend on the actual value,
>> + * so it can be changed to a different heuristic later if needed.
>> + */
>> +#define KHO_EXT_BLKSIZE		SZ_1G
>> +#define KHO_EXT_SHIFT		const_ilog2(KHO_EXT_BLKSIZE)
>
> Nit: EXT_ what? ;-)
>
>> +
>> +/* Called for the KHO preserved memory radix tree. */
>> +static int __init kho_ext_walk_leaf(unsigned long key, void *data)
>
> I have to say this function still confuses me :)

Honestly, I think this whole tree walking API makes things really hard
to reason about. I think we should replace it with something like
kho_radix_for_each(). It would improve code readability a lot.

I plan to do it at some point, but not as a part of this series.

>
>> +{
>> +	/* Radix tree tracking free blocks. */
>> +	struct kho_radix_tree *tree = data;
>> +	phys_addr_t start, end;
>> +	unsigned int order;
>> +	int err;
>> +
>> +	start = kho_decode_radix_key(key, &order);
>
> I would add a comment here, that the key is from the memory tracker and
> it is decoded to an address.

ACK, will add.

-- 
Regards,
Pratyush Yadav


  reply	other threads:[~2026-07-24 16:54 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-09 17:37 [PATCH v3 00/21] kho: make boot time huge page allocation work nicely with KHO Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 01/21] kho: generalize radix tree APIs Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 02/21] kho: make radix max key width more obvious Pratyush Yadav
2026-07-15  9:35   ` Mike Rapoport
2026-07-09 17:37 ` [PATCH v3 03/21] kho: disallow wide keys in radix tree Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 04/21] kho: return virtual address of mem_map Pratyush Yadav
2026-07-15  9:35   ` Mike Rapoport
2026-07-24 16:45     ` Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 05/21] kho: store incoming radix tree in kho_in Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 06/21] kho: move all memory retrieval logic to kho_mem_retrieve() Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 07/21] kho: add a struct for radix callbacks Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 08/21] kho: add callback for table pages Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 09/21] kho: add data argument to radix walk callback Pratyush Yadav
2026-07-09 17:37 ` [PATCH v3 10/21] kho: allow early-boot usage of the KHO radix tree Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 11/21] kho: allow destroying " Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 12/21] kho: add kho_radix_init_tree() Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 13/21] kho: expose kho_scratch_overlap() to kexec_handover.h Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 14/21] kho: initialize kho_scratch pointer earlier in boot Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 15/21] kho: initialize preserved memory map radix tree earlier Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 16/21] mm/mm_init: init deferred page migratetype in deferred_init_pages() Pratyush Yadav
2026-07-15  9:35   ` Mike Rapoport
2026-07-09 17:38 ` [PATCH v3 17/21] mm/mm_init: don't rely on memblock to get KHO scratch migratetype Pratyush Yadav
2026-07-15  9:35   ` Mike Rapoport
2026-07-09 17:38 ` [PATCH v3 18/21] kho: extend scratch Pratyush Yadav
2026-07-15  9:35   ` Mike Rapoport
2026-07-24 16:54     ` Pratyush Yadav [this message]
2026-07-09 17:38 ` [PATCH v3 19/21] memblock: make HugeTLB bootmem allocation work with KHO Pratyush Yadav
2026-07-15  9:35   ` Mike Rapoport
2026-07-24 16:51     ` Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 20/21] memblock: add memblock_reserved_hugetlb_size() Pratyush Yadav
2026-07-09 17:38 ` [PATCH v3 21/21] kho: exclude hugetlb memory from scratch size calculation Pratyush Yadav

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2vxzjyqkgwgk.fsf@kernel.org \
    --to=pratyush@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=david@kernel.org \
    --cc=graf@amazon.com \
    --cc=jasonmiu@google.com \
    --cc=jloeser@linux.microsoft.com \
    --cc=kexec@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=muchun.song@linux.dev \
    --cc=osalvador@suse.de \
    --cc=pasha.tatashin@soleen.com \
    --cc=rppt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.