Linux memory from 0 to 1 learning notes (VI, physical memory initialization IV - memory allocator) - continuous update

Write in front

At the moment of linux startup, memory management has already started. In the kernel, allocator s that implement physical memory management include:

  • Initialization phase physical memory management memblock

  • Continuous physical memory management buddy allocator

  • Discontinuous physical memory management vmalloc allocator

  • Small physical memory management slab allocator

In the system initialization phase, a bootmem allocator and a memblock allocator will be enabled first. The bootmem allocator manages all the memory of a node node, including multiple bootmems in multiple nodes in numa architecture, which are linked to bdata_list is saved in the linked list. The initialization of the partner system is to release all the physical page boxes managed by bootmem to the partner system.

Next, let's briefly sort out the initialization process of the memory allocator (red part);

I. initialize buddy system

Each physical page (page frame) in the system memory corresponds to a struct page instance. Each memory domain is associated with an instance of struct zone. It holds the main array used to manage partner data.

mmzone.h

struct zone{

...

//Free area of no length

struct free_area free_area[MAX_ORDER];

...

};

free_area is an auxiliary data structure. It is defined as follows:

<mmzone.h>

struct free_area{

    struct list_head_head free_list[MIGRATE_TYPES];

    unsigned long nr_free;

};

nr_free specifies the number of empty free page blocks in the current memory area.

free_list is a linked list used to link free pages.

Order is a very important term in partner system. Describes the quantity unit of memory allocation. The length of the memory block is the order power of 2. The range of order is from 0 to MAX_ORDER.

26  /* Free memory management - zoned buddy allocator.  */
27  #ifndef CONFIG_FORCE_MAX_ZONEORDER
28  #define MAX_ORDER 11
29  #else
30  #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
31  #endif
32  #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))

MAX_ The order setting is 11.

1.1 mem_init()

linux_mainline-5.17.0/arch/arm64/mm/init.c
374  void __init mem_init(void)
375  {
376  	if (swiotlb_force == SWIOTLB_FORCE ||
377  	    max_pfn > PFN_DOWN(arm64_dma_phys_limit))
378  		swiotlb_init(1);
379  	else if (!xen_swiotlb_detect())
380  		swiotlb_force = SWIOTLB_NO_FORCE;
381  
382  	/* this will put all unused low memory onto the freelists */
                //Partner system is a method to manage memory using page as a unit. Before the partner system takes over, deal with and establish mem_ For the section structure, the memory that is no longer used must be released from the Mem Block and handed over to the partner system for management
383  	memblock_free_all();
384  
385  	/*
386  	 * Check boundaries twice: Some fundamental inconsistencies can be
387  	 * detected at build time already.
388  	 */
389  #ifdef CONFIG_COMPAT
390  	BUILD_BUG_ON(TASK_SIZE_32 > DEFAULT_MAP_WINDOW_64);
391  #endif
392  
393  	/*
394  	 * Selected page table levels should match when derived from
395  	 * scratch using the virtual address range and page size.
396  	 */
397  	BUILD_BUG_ON(ARM64_HW_PGTABLE_LEVELS(CONFIG_ARM64_VA_BITS) !=
398  		     CONFIG_PGTABLE_LEVELS);
399  
400  	if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
401  		extern int sysctl_overcommit_memory;
402  		/*
403  		 * On a machine this small we won't get anywhere without
404  		 * overcommit, so turn it on by default.
405  		 */
406  		sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
407  	}
408  }

1.2 memblock_free_all()

Free pages to buddy allocator

linux_mainline-5.17.0/mm/memblock.c
2101  /**
2102   * memblock_free_all - release free pages to the buddy allocator
2103   */
2104  void __init memblock_free_all(void)
2105  {
2106  	unsigned long pages;
2107  
2108  	free_unused_memmap();//Release unused mem_map memory
2109  	reset_all_zones_managed_pages();//Manage all nodes and all regions_ Pages is automatically set to 0 (managed_pages indicates the number of pages managed by the partner system).
2110  
2111  	pages = free_low_memory_core_early();//Mark the page corresponding to the memblock of the reserved type and the memory explicitly marked as Memory None as reserved(PG_reserved) Free the area of memory block type as memory and mark it as a free page
2112  	totalram_pages_add(pages);//Increase_ totalram_pages, used to mark the total number of pages available in the system
2113  }

1.3 buddy allocation page

alloc_page(mask, order), allocate an order power of 2 and return an instance of struct page.

get_zeroed_page(mask), allocate a page and return a page instance.

__ get_free_page(mask,order) and__ get_free_page(mask), which returns the virtual address of the allocated memory block.

get_dma_pages(gfp_mask,order) to return the obtained DMA page.

1.4 buddy release page

free_page(struct page *) and free_pages(struct page *, order) is used to return one or two pages to the order power to the memory management subsystem.

__ free_page(struct page *) and__ free_ The meaning of pages (struct, Page *, order) is the same as above, but when it refers to the memory area to be released, the virtual address is used instead of the page instance.

2, Initialize Slab allocator

kmem_cache_init() mainly completes the initialization of the kernel slub memory allocation system.

huang:
linux_mainline-5.17.0/mm/slab.c
//slab (slub) initialization
1199  /*
1200   * Initialisation.  Called after the page allocator have been initialised and
1201   * before smp_init().
1202   */
1203  void __init kmem_cache_init(void)
1204  {
1205  	int i;
1206    //kmem_cache_init creates the first slab cache in the system for kmem_ The instance of cache provides memory. For this purpose, the kernel mainly uses static data created at compile time. In fact, a static data structure (initarray_cache) is used as a per CPU array. The name of the cache is kmem_cache_boot. 
1207  	kmem_cache = &kmem_cache_boot;
1208  
1209  	if (!IS_ENABLED(CONFIG_NUMA) || num_possible_nodes() == 1)
1210  		use_alien_caches = 0;
1211  
1212  	for (i = 0; i < NUM_INIT_LISTS; i++)
1213  		kmem_cache_node_init(&init_kmem_cache_node[i]);
1214  
1215  	/*
1216  	 * Fragmentation resistance on low memory - only use bigger
1217  	 * page orders on machines with more than 32MB of memory if
1218  	 * not overridden on the command line.
1219  	 */
1220  	if (!slab_max_order_set && totalram_pages() > (32 << 20) >> PAGE_SHIFT)
1221  		slab_max_order = SLAB_MAX_ORDER_HI;
1222  
1223  	/* Bootstrap is tricky, because several objects are allocated
1224  	 * from caches that do not exist yet:
1225  	 * 1) initialize the kmem_cache cache: it contains the struct
1226  	 *    kmem_cache structures of all caches, except kmem_cache itself:
1227  	 *    kmem_cache is statically allocated.
1228  	 *    Initially an __init data area is used for the head array and the
1229  	 *    kmem_cache_node structures, it's replaced with a kmalloc allocated
1230  	 *    array at the end of the bootstrap.
1231  	 * 2) Create the first kmalloc cache.
1232  	 *    The struct kmem_cache for the new cache is allocated normally.
1233  	 *    An __init data area is used for the head array.
1234  	 * 3) Create the remaining kmalloc caches, with minimally sized
1235  	 *    head arrays.
1236  	 * 4) Replace the __init data head arrays for kmem_cache and the first
1237  	 *    kmalloc cache with kmalloc allocated arrays.
1238  	 * 5) Replace the __init data for kmem_cache_node for kmem_cache and
1239  	 *    the other cache's with kmalloc allocated memory.
1240  	 * 6) Resize the head arrays of the kmalloc caches to their final sizes.
1241  	 */
1242  
1243  	/* 1) create the kmem_cache */
1244  
1245  	/*
1246  	 * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
1247  	 */
        //Call create_boot_cache creates a file named kmem_cache cache And add to slab_caches are in the chain
1248  	create_boot_cache(kmem_cache, "kmem_cache",
1249  		offsetof(struct kmem_cache, node) +
1250  				  nr_node_ids * sizeof(struct kmem_cache_node *),
1251  				  SLAB_HWCACHE_ALIGN, 0, 0);
1252  	list_add(&kmem_cache->list, &slab_caches);
1253  	slab_state = PARTIAL;
1254  
1255  	/*
1256  	 * Initialize the caches that provide memory for the  kmem_cache_node
1257  	 * structures first.  Without this, further allocations will bug.
1258  	 */
1259  	kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE] = create_kmalloc_cache(
1260  				kmalloc_info[INDEX_NODE].name[KMALLOC_NORMAL],
1261  				kmalloc_info[INDEX_NODE].size,
1262  				ARCH_KMALLOC_FLAGS, 0,
1263  				kmalloc_info[INDEX_NODE].size);
1264  	slab_state = PARTIAL_NODE;
1265  	setup_kmalloc_cache_index_table();
1266  
1267  	slab_early_init = 0;
1268  
1269  	/* 5) Replace the bootstrap kmem_cache_node */
1270  	{
1271  		int nid;
1272  
1273  		for_each_online_node(nid) {
1274  			init_list(kmem_cache, &init_kmem_cache_node[CACHE_CACHE + nid], nid);
1275  
1276  			init_list(kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE],
1277  					  &init_kmem_cache_node[SIZE_NODE + nid], nid);
1278  		}
1279  	}
1280  
1281  	create_kmalloc_caches(ARCH_KMALLOC_FLAGS);
1282  }

Tags: Memory

Posted by muthuraj_mr on Thu, 14 Apr 2022 23:44:34 +0930