xc_domain_populate_physmap()
Overview
xenguest uses
xc_domain_populate_physmap()
to populate a Xen domain’s physical memory map:
Both call the XENMEM_populate_physmap
hypercall.
xc_domain_populate_physmap_exact()
also sets the “exact” flag
for allocating memory only on the given NUMA node.
This is a very simplified overview of the hypercall:
flowchart LR subgraph hypercall handlers populate_physmap("<tt>populate_physmap()</tt> One call for each memory range (extent)") end subgraph "Xen buddy allocator:" populate_physmap --> alloc_domheap_pages("<tt>alloc_domheap_pages()</tt> Assign allocated pages to the domain") alloc_domheap_pages --> alloc_heap_pages("<tt>alloc_heap_pages()</tt> If needed: split high-order pages into smaller buddies, and scrub dirty pages") --> get_free_buddy("<tt>get_free_buddy()</tt> If reqested: Allocate from a preferred/exact NUMA node and/or from unscrubbed memory ") end click populate_physmap "https://github.com/xen-project/xen/blob/e16acd80/xen/common/memory.c#L159-L314 " _blank click alloc_domheap_pages "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L2641-L2697 " _blank click get_free_buddy "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L855-L958 " _blank click alloc_heap_pages "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L967-L1116 " _blank
memory_op(XENMEM_populate_physmap)
It calls
construct_memop_from_reservation()
to convert the arguments for allocating a page from
struct xen_memory_reservation
to struct memop_args
and
passes
it to
populate_physmap():
construct_memop_from_reservation()
It populates struct memop_args
using the
hypercall arguments. It:
- Copies
extent_start
,nr_extents
, andextent_order
. - Populates
memop_args->memflags
using the givenmem_flags
.
Converting a vNODE to a pNODE for vNUMA
When a vNUMA vnode is passed using XENMEMF_vnode
, and domain->vnuma
and domain->vnuma->nr_vnodes
are set, and the
vnode
(virtual NUMA node) maps to a pnode
(physical NUMA node), it also:
- Populates the
pnode
in thememflags
of thestruct memop_args
- and sets a
XENMEMF_exact_node_request
in them as well.
propagate_node()
If no vNUMA node is passed, construct_memop_from_reservation()
calls
propagate_node()
to propagate the NUMA node and XENMEMF_exact_node_request
for use in Xen.
populate_physmap()
It handles hypercall preemption and resumption after a preemption, keeps track of the already populated pages.
For each range (extent), it runs an iteration of the allocation loop. It passes the
struct domain
- page order
- count remaining pages populate
- and the converted
memflags
alloc_domheap_pages()
It calls alloc_heap_pages() and on success, assigns the allocated pages to the domain.
alloc_heap_pages()
It calls get_free_buddy()[^1] to allocate a page at the most suitable place: When no pages of the requested size are free, it splits larger superpages into pages of the requested size.
get_free_buddy()
It finds memory based on the flags and domain and return its page struct
:
- Optionally allocate prefer to allocate from a passed NUMA node
- Optionally allocate from the domain’s next affine NUMA node (round-robin)
- Optionally return if the preferred NUMA allocation did not succeed
- Optionally allocate from not-yet scrubbed memory
- Optionally allocate from the given range of memory zones
- Fall back allocate from the next NUMA node on the system (round-robin)
For details see the get_free_buddy() finds memory based on the flags and domain.
Full flowchart
flowchart TD subgraph XenCtrl xc_domain_populate_physmap["<tt>xc_domain_populate_physmap()"] xc_domain_populate_physmap_exact["<tt>xc_domain_populate_physmap_exact()"] end subgraph Xen %% sub-subgraph from memory_op() to populate_node() and back xc_domain_populate_physmap & xc_domain_populate_physmap_exact <--reservation,<br>and for preempt:<br>nr_start/nr_done--> memory_op("<tt>memory_op(XENMEM_populate_physmap)") memory_op --struct xen_memory_reservation--> construct_memop_from_reservation("<tt>construct_memop_from_reservation()") --struct<br>xen_memory_reservation->mem_flags--> propagate_node("<tt>propagate_node()") --_struct<br>memop_args->memflags_--> construct_memop_from_reservation --_struct memop_args_--> memory_op<--struct memop_args *: struct domain *, List of extent base addrs, Number of extents, Size of each extent (extent_order), Allocation flags(memflags)--> populate_physmap[["<tt>populate_physmap()"]] <-.domain, extent base addrs, extent size, memflags, nr_start and nr_done.-> populate_physmap_loop--if memflags & MEMF_populate_on_demand -->guest_physmap_mark_populate_on_demand(" <tt>guest_physmap_mark_populate_on_demand()") populate_physmap_loop@{ label: "While extents to populate, and not asked to preempt, for each extent left to do:", shape: notch-pent } --domain, order, memflags--> alloc_domheap_pages("<tt>alloc_domheap_pages()") --zone_lo, zone_hi, order, memflags, domain--> alloc_heap_pages --zone_lo, zone_hi, order, memflags, domain--> get_free_buddy("<tt>get_free_buddy()") --_page_info_ -->alloc_heap_pages --if no page--> no_scrub("<tt>get_free_buddy(MEMF_no_scrub)</tt> (honored only when order==0)") --_dirty 4k page_ -->alloc_heap_pages <--_dirty 4k page_--> scrub_one_page("<tt>scrub_one_page()") alloc_heap_pages("<tt>alloc_heap_pages()</tt> (also splits higher-order pages into smaller buddies if needed)") --_page_info_ -->alloc_domheap_pages --page_info, order, domain, memflags-->assign_page("<tt>assign_page()") assign_page --page_info, nr_mfns, domain, memflags--> assign_pages("<tt>assign_pages()") --domain, nr_mfns--> domain_adjust_tot_pages("<tt>domain_adjust_tot_pages()") alloc_domheap_pages --_page_info_--> populate_physmap_loop --page(gpfn, mfn, extent_order)--> guest_physmap_add_page("<tt>guest_physmap_add_page()") populate_physmap--nr_done, preempted-->memory_op end click memory_op "https://github.com/xen-project/xen/blob/e16acd80/xen/common/memory.c#L1409-L1425 " _blank click construct_memop_from_reservation "https://github.com/xen-project/xen/blob/e16acd80/xen/common/memory.c#L1022-L1071 " _blank click propagate_node "https://github.com/xen-project/xen/blob/e16acd80/xen/common/memory.c#L524-L547 " _blank click populate_physmap "https://github.com/xen-project/xen/blob/e16acd80/xen/common/memory.c#L159-L314 " _blank click populate_physmap_loop "https://github.com/xen-project/xen/blob/e16acd80/xen/common/memory.c#L197-L304 " _blank click guest_physmap_mark_populate_on_demand "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L210-220 " _blank click guest_physmap_add_page "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L296 " _blank click alloc_domheap_pages "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L2641-L2697 " _blank click alloc_heap_pages "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L967-L1116 " _blank click get_free_buddy "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L855-L958 " _blank click assign_page "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L2540-L2633 " _blank click assign_pages "https://github.com/xen-project/xen/blob/e16acd80/xen/common/page_alloc.c#L2635-L2639 " _blank