Linux kernel series: paths to memblock_double_array
This post discusses the internal details of some memblock
functions—specifically, functions that may trigger memblock_double_array()
. The goal is to explain it in such a way that a beginner C or C++ programmer unfamiliar with the Linux kernel can comprehend it. I discussed the basics of memblock
previously.
Looking at memblock.c
, we see that memblock_double_array()
is called by memblock_add_range()
and memblock_isolate_range()
. These are both internal functions with no prototype in memblock.h
. By internal function, I mean a function that is called by a function in memblock.h
or memblock.c
.
memblock_add_range()
makes two passes through a portion of its code.[1] In the first pass, it determines nr_new
, the number of new regions that need to be added. It then calls memblock_double_array()
if the current number of memblock_type *type
regions plus nr_new
exceeds the current size of that type’s regions
array.
memblock_isolate_range()
splits memblock regions that overlap with a given range at the boundaries of the range.[2] It calls memblock_double_array()
if the current number of memblock_type *type
regions plus 2 exceeds the current size of that type’s regions
array, since at most two additional regions will be created by the splits.
We can trace memblock_add_range()
and memblock_isolate_range()
upwards until we find the external functions (those with prototypes in memblock.h
) that can trigger memblock_double_array()
.
memblock_add_range()
memblock_add_range()
is called by:
memblock_add_node()
: external function[3]memblock_add()
: external functionmemblock_reserve()
: external and internal functionmemblock_physmem_add()
: external function
By external and internal function, I mean a function that has a prototype in memblock.h
and is called in memblock.c
or memblock.h
.
memblock_reserve()
memblock_reserve()
is called by:
memblock_double_array()
memblock_alloc_range_nid()
: external and internal function
memblock_alloc_range_nid()
memblock_alloc_range_nid()
is called by:
memblock_phys_alloc_range()
: external and internal function called by:memblock_phys_alloc()
: external function
memblock_phys_alloc_try_nid()
: external functionmemblock_alloc_internal()
: internal function called by:memblock_alloc_exact_nid_raw()
: external functionmemblock_alloc_try_nid_raw()
: external and internal function called by:memblock_alloc_raw()
: external function
memblock_alloc_try_nid()
: external and internal function called by:memblock_alloc()
: external functionmemblock_alloc_from()
: external functionmemblock_alloc_low()
: external functionmemblock_alloc_node()
: external function
memblock_isolate_range()
This one is a bit more complicated. memblock_isolate_range()
is called by:
memblock_remove_range()
: internal functionmemblock_setclr_flag()
: internal functionmemblock_set_node()
: external functionmemblock_cap_memory_range()
: external and internal function
memblock_remove_range()
memblock_remove_range()
is called by:
memblock_remove()
: external functionmemblock_phys_free()
: external function and internal functionmemblock_enforce_memory_limit()
: external functionmemblock_cap_memory_range()
memblock_phys_free()
memblock_phys_free()
is called by:
memblock_free()
: external function and internal function called by:memblock_double_array()
free_memmap()
: internal function called by:free_unused_memmap()
: internal function called by:memblock_free_all()
: external function
memblock_setclr_flag()
Each memblock_region
has a set of memblock_flags
. memblock_setclr_flag()
uses memblock_isolate_range()
to isolate a specific region so that it can set or clear flags for that region. The regions are re-merged at the end of the function, so there is no net increase in the number of regions.
memblock_setclr_flag()
is called by:
memblock_mark_hotplug()
: external functionmemblock_clear_hotplug()
: external function and internal function called by:free_low_memory_core_early()
: internal function called bymemblock_free_all()
memblock_mark_mirror()
: external functionmemblock_mark_nomap()
: external functionmemblock_clear_nomap()
: external function
memblock_cap_memory_range()
memblock_cap_memory_range()
is called by:
memblock_mem_limit_remove_map()
: external function
External functions
Thus, most of the external functions in memblock can trigger memblock_double_array()
. This includes:
memblock_add_node()
memblock_add()
memblock_reserve()
memblock_physmem_add()
memblock_alloc_range_nid()
memblock_phys_alloc_range()
memblock_phys_alloc()
memblock_phys_alloc_try_nid()
memblock_alloc_exact_nid_raw()
memblock_alloc_try_nid_raw()
memblock_alloc_raw()
memblock_alloc_try_nid()
memblock_alloc()
memblock_alloc_from()
memblock_alloc_low()
memblock_alloc_node()
memblock_set_node()
memblock_cap_memory_range()
memblock_remove()
memblock_phys_free()
memblock_enforce_memory_limit()
memblock_free()
memblock_free_all()
memblock_mark_hotplug()
memblock_clear_hotplug()
memblock_mark_mirror()
memblock_mark_nomap()
memblock_clear_nomap()
memblock_mem_limit_remove_map()