源码基于:Linux5.4
0. 前言
在 zone初始化一文中简单剖析了 zone 的初始化流程,也是继 memblock初始化 和 SPARSEMEM初始化 之后有一个内存管理层,而zone 这一层管理层中,所有的物理内存都会被添加到zone 中的成员变量 free_area 数组管理,而它就是buddy 系统管理的核心数据结构。
memblock初始化、SPARSEMEM初始化、zone 初始化 进行了内存管理的初始化流程,而经过bootmem管理、paging_init 的内核内存映射、sparse 模型创建、zone 数据结构和buddy 数据结构初始化完成后,需要通过 mm_init() 对内存进行最后的初始化工作,将内存管理从 bootmem移交到 buddy 系统和 LRU。
由于 slab 系统初始化前,Linux 内核已经完成了伙伴系统的初始化工作,内核可以很方便地通过伙伴系统提供内存。但是slab系统初始化时需要定义一些基本的数据结构来维护和管理slab系统 (如slab cache描述符 struct kmem_cache)。像 stcuct kmem_cache这些数据结构需要小块内存进行存储,且这些小块内存往往只有几十或者几百字节远远小于一个页的大小。若通过伙伴系统分配内存来存储着这些数据结构,则违背了slab系统设计的初衷(内存资源浪费,内存分配效率低下)。所以我们只能通过slab系统给struct kmem_cache结构体分配slab缓存,然后从刚分配的slab缓存中去获取对应的slab obj(小块内存)来存储struct kmem_cache结构中的数据。看到这里已经懵逼了,在slab系统中slab缓存的描述符就是strcut kmem_cache。此时 slab 系统还未开始初始化,也就是 struct kmem_cache还没有呢,又怎么能从slab系统中分配到小块内存呢?这活生生的一个是鸡生蛋,蛋生鸡的问题啊(slab系统只能在slab系统初始化完成后初始化),貌似无解???
机智的 Linux内核使用了一个特殊的技巧来解决上面slab系统初始化时遇到的问题。
linux内核镜像编译时创建的静态数据会在内核内存初始化时就会被加载到内存中去,后续内核使用该静态数据时并不需要分配内存来存储它。Linux 利用这一特性,使用了编译时创建的静态结构boot_kmem_cache 数据来作为系统中的第一个 slab 缓存,用它来为创建 struct kmem_cache时分配小块内存。
在 mm_init() 中的 mem_init() 会free memblock ,并对 buddy 系统的 free areas 进行最后的初始化,至此buddy 系统创建完成。在 mem_init() 完成之后会调用 kmem_cache_init(),完成 kmem_cache_node、kmem_cache、kmalloc_caches 三个 slab cache 管理结构的初始化。
当然,需要注意的是mm_init() 之后slab 分配器,还会调用 kmem_cache_init_late() 进一步初始化,slob 只是标记 slab_state 为FULL,slub 中空实现。
总的初始化流程大致为:
start_kernel()
---->mm_init()
---->mem_init()
---->kmem_cache_init()
---->kmem_cache_init_late()
本文将中重点分析 UMA 架构下的 slub 分配器的初始化流程。
转自:https://justinwei.blog.csdn.net/article/details/127785111