arm64内存-kmem_cache-slub-分配器-结构体和框架

 

上一篇 :  arm64内存-memblock交接内存给zoned frame allocator (buddy system)

https://www.cnblogs.com/zhangzhiwei122/p/16100012.html

 

start_kernel -> mm_init -> kmem_cache_init

启动过程,就是各种初始化,前面 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();

 

slub 结构体和框架

参考:

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

框架

 

 

 

说明: 

1、 kmem_cache 中的 list 将所有的 kmem 对象都加入到链表中; 

2、kmem_cache 中  cpu_slab 是 per cpu 类型的指针,不同 CPU 访问时,会指向 不同的 kmem_cache_cpu 对象。所以用 蓝色 4 个 表示。

3、struct page 在不同的情况下,有不同的内容 ;

           由 struct kmem_cache_node 中的 partial 指向的 page 中,有  slab_list 字段,指向下一个 pageblock 。 

           由 struct kmem_cache_cpu 中page 指向的 page 中,freelist 不起作用 ;

           由struct kmem_cache_cpu 中 partial 指向的 page 中,具有 page * next 字段生效,指向下一个 page 。  

 

4、https://www.cnblogs.com/linhaostudy/p/10426599.html  这儿由超级赞的 SLUB 框架图。 上面我自己画的,就班门弄斧啦!

结构体

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 对象。

 

下一篇:arm64内存-slub分配器-转载两篇优秀博文

https://www.cnblogs.com/zhangzhiwei122/p/16102021.html

 

posted @ 2022-04-05 12:55  张志伟122  阅读(412)  评论(0编辑  收藏  举报