上一篇 : arm64内存-memblock交接内存给zoned frame allocator (buddy system)
https://www.cnblogs.com/zhangzhiwei122/p/16100012.html
启动过程,就是各种初始化,前面 mem_init 刚把 buddy system 初始化搞完,下面的 kmem_cache_init 就开始了。
初始化过程知识密度太大了,一行 xx_init 语句,后面就隐藏着一座冰山,没有充足的背景知识,真的很难梳理下去。
kernel memeory cache init - 内核 内存 缓存 初始化。
背景: 在内核空间,也需要 提供 类似 malloc / free 接口的 内存分配器,不然在需要申请小对象时就只能分配一整页了;同时,内核对对象的管理又有一定的特殊性,有些对象的访问非常频繁,需要采用缓冲机制。
所以,名字就是 k mem cache init 。
818/* 819 * Set up kernel memory allocators 820 */ 821static void __init mm_init(void) 822{ 823 /* 824 * page_ext requires contiguous pages, 825 * bigger than MAX_ORDER unless SPARSEMEM. 826 */ 827 page_ext_init_flatmem(); 828 init_debug_pagealloc(); 829 report_meminit(); 830 mem_init(); 831 kmem_cache_init();
参考:
https://www.cnblogs.com/LoyenWang/p/11922887.html
https://blog.csdn.net/chenying126/article/details/78451344
https://blog.csdn.net/weixin_29746595/article/details/116930296
to be done
mm/slab.h
slab_state - slab 分配器初始化过程的各个阶段。 DOWN = 0 ,即默认阶段。 kmem_cache_init 里面会,随着初始化,会 修改 66 行 的 slab_state 全局变量。
57 */ 58enum slab_state { 59 DOWN, /* No slab functionality yet */ 60 PARTIAL, /* SLUB: kmem_cache_node available */ 61 PARTIAL_NODE, /* SLAB: kmalloc size for node struct available */ 62 UP, /* Slab caches usable but not all extras yet */ 63 FULL /* Everything is working */ 64}; 65 66extern enum slab_state slab_state;
kmem_cache 结构体
一个 kmem_cache 对象,管理 相同 size 的 很多对象 。
这 应该属于 : pool 类型内存分配
举例: 先申请出来 1024 个 32 字节的对象; 512 个 64字节的对象;
alloc(size = 12 ) 时,对 size 进行 roundup (找到 32 自己的 pool ), 从pool 中 取 一个没有使用的,丢出去)
107 行, char * name 是 缓存对象管理器 的名称。
88 · 89 记录 被管理对象的 size 信息。这个 kmem_cache 对象分配和回收 都时按照 这个 size 信息来进行的。里面管理的就是 相同大小(大小为 size) 的对象。
96 行 - oo 里面,高 16 bits 记录 order 值; 低 16 bits 记录 缓存对象的 总个数。
108 - list 将系统中,所有的 kmem_cache 对象都 链接 起来。
83struct kmem_cache { 84 struct kmem_cache_cpu __percpu *cpu_slab; 85 /* Used for retrieving partial slabs, etc. */ 86 slab_flags_t flags; 87 unsigned long min_partial; 88 unsigned int size; /* The size of an object including metadata */ 89 unsigned int object_size;/* The size of an object without metadata */ 91 unsigned int offset; /* Free pointer offset */ 92#ifdef CONFIG_SLUB_CPU_PARTIAL 93 /* Number of per cpu partial objects to keep around */ 94 unsigned int cpu_partial; 95#endif 96 struct kmem_cache_order_objects oo; 97 98 /* Allocation and freeing of slabs */ 99 struct kmem_cache_order_objects max; 100 struct kmem_cache_order_objects min; 101 gfp_t allocflags; /* gfp flags to use on each alloc */ 102 int refcount; /* Refcount for slab cache destroy */ 103 void (*ctor)(void *); 104 unsigned int inuse; /* Offset to metadata */ 105 unsigned int align; /* Alignment */ 106 unsigned int red_left_pad; /* Left redzone padding size */ 107 const char *name; /* Name (only for display!) */ 108 struct list_head list; /* List of slab caches */ 109#ifdef CONFIG_SYSFS 110 struct kobject kobj; /* For sysfs */ 111#endif 130 131 unsigned int useroffset; /* Usercopy region offset */ 132 unsigned int usersize; /* Usercopy region size */ 133 134 struct kmem_cache_node *node[MAX_NUMNODES]; 135};
示例 - 1 :
arch/arm64/mm/pgd.c 中,构建了一个名为 pgd_cache 的 缓存对象管理器。 它管理的就是 size 为 PGD_SIZE 的对象。
之后,想要 alloc 时,分配出来的就是 PGD_SIZE 大小的一个空间。
18static struct kmem_cache *pgd_cache __ro_after_init; 38void __init pgtable_cache_init(void) 39{ 54 pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE, 55 SLAB_PANIC, NULL); 56}
示例 - 2 mm/slab_common.c 中
name 为 kmalloc-96 的 kmem_cache 对象,管理 大小为 96 字节的对象 的缓存;
name 为 kmalloc-1k 的 kmem_cache 对象,管理 大小为 1024 字节的对象 的缓存;
……
这样的 kmalloc-xx 有 8 ,16, 32, 64,128 ,…… 67108864, kmalloc-96, kmalloc-192 这么多
kmalloc( size ) 是,其实就是 roundup ( size ) 找到 找到 合适的 kmalloc-xx 缓存管理器,从里面分配 对象 。
kernel 中,所有的 缓存管理器对象,都通过 list 链接起来 。
kmem_cache_cpu 结构体
42struct kmem_cache_cpu { 43 void **freelist; /* Pointer to next available object */ 44 unsigned long tid; /* Globally unique transaction id */ 45 struct page *page; /* The slab from which we are allocating */ 46#ifdef CONFIG_SLUB_CPU_PARTIAL 47 struct page *partial; /* Partially allocated frozen slabs */ 48#endif 52};
kmem_cache 中 struct kmem_cache_cpu __percpu *cpu_slab; 指向的对象。
在 4 个CPU的系统上面,
1 个 kmem_cache 对象, 需要创建 4 个 kmem_cache_cpu 对象。每个cpu 取自己的 kmem_cache_cpu 对象,然后从里面 分配 对象 出来。
43 freelist 指向 空闲的(未被分配出去的) 对象【加速分配:下次分配是,发现 freelist 非空,就可以直接分配它出去了】
45 ~ 47 指向 struct page 对象。 这个 struct page 里面,记录了 所有管理 的 对象 的地址 信息。
kmem_cache_node
记录 一个 节点 (node)上面的 缓存对象 的存放 信息
548struct kmem_cache_node { 549 spinlock_t list_lock; 550 566#ifdef CONFIG_SLUB 567 unsigned long nr_partial; 568 struct list_head partial; 574#endif 576};
struct kmem_cache_node *node[MAX_NUMNODES]; 中的指针指向的对象 。
UMA 系统上面,MAX_NUMNODES 为 1,即 1 个 kmem_cache 对象,需要分配 1 个 kmem_cache_node 对象 。
567 nr_partial 记录了 页块 (用于存放 对象 ) 的个数。
568 partial 用于 将多个 页块 组成 list .
struct page
1 struct page { 2 union { 3 void *s_mem; /* slab first object */ 4 }; 5 6 /* Second double word */ 7 union { 8 void *freelist; /* sl[aou]b first free object */ 9 }; 10 11 union { 12 struct { 13 union { 14 struct { /* SLUB */ 15 unsigned inuse:16; 16 unsigned objects:15; 17 unsigned frozen:1; 18 }; 19 }; 20 }; 21 }; 22 23 /* 24 * Third double word block 25 */ 26 union { 27 struct { /* slub per cpu partial pages */ 28 struct page *next; /* Next partial slab */ 29 int pages; /* Nr of partial slabs left */ 30 int pobjects; /* Approximate # of objects */ 31 }; 32 33 struct rcu_head rcu_head; /* Used by SLAB 34 * when destroying via RCU 35 */ 36 }; 37 struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */ 38 }
3 - s_mem 指向 page 对应 的 物理页 映射后 的虚拟地址 。物理页就是用来存放 对象 空间。
8 - freelist - 指向 第一个 空闲对象 。
14~ 18 SLUB 模型中使用,inuse - 使用的 对象数目, objects - 总共的对象数目; fronzen - 标识是 kmem_cache_cpu 中指向的 page ;还是 node 中指向的page .
27 ~ 31 SLUB模型的 kmem_cache_cpu 对象的 partial 指向的 page 页 才具有的属性。
37 - slab_cache 指向 这个page 所属的 kmem_cache 对象。